@signalwire/js 4.0.0-beta.11 → 4.0.0-beta.12
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/browser.mjs +1171 -563
- package/dist/browser.mjs.map +1 -1
- package/dist/browser.umd.js +1173 -563
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +994 -385
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +408 -68
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +408 -68
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +985 -378
- package/dist/index.mjs.map +1 -1
- package/dist/operators/index.cjs +1 -1
- package/dist/operators/index.mjs +1 -1
- package/dist/{operators-B1xH6k06.mjs → operators-CX_lCCJm.mjs} +2 -2
- package/dist/{operators-B1xH6k06.mjs.map → operators-CX_lCCJm.mjs.map} +1 -1
- package/dist/{operators-BT3jl--r.cjs → operators-D6a2J1KA.cjs} +2 -2
- package/dist/{operators-BT3jl--r.cjs.map → operators-D6a2J1KA.cjs.map} +1 -1
- package/package.json +1 -1
package/dist/browser.umd.js
CHANGED
|
@@ -461,9 +461,9 @@ var require_Subscriber = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
461
461
|
var NotificationFactories_1 = require_NotificationFactories();
|
|
462
462
|
var timeoutProvider_1 = require_timeoutProvider();
|
|
463
463
|
var errorContext_1$2 = require_errorContext();
|
|
464
|
-
var Subscriber
|
|
465
|
-
__extends$16(Subscriber$
|
|
466
|
-
function Subscriber$
|
|
464
|
+
var Subscriber = function(_super) {
|
|
465
|
+
__extends$16(Subscriber$1, _super);
|
|
466
|
+
function Subscriber$1(destination) {
|
|
467
467
|
var _this = _super.call(this) || this;
|
|
468
468
|
_this.isStopped = false;
|
|
469
469
|
if (destination) {
|
|
@@ -472,54 +472,54 @@ var require_Subscriber = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
472
472
|
} else _this.destination = exports.EMPTY_OBSERVER;
|
|
473
473
|
return _this;
|
|
474
474
|
}
|
|
475
|
-
Subscriber$
|
|
475
|
+
Subscriber$1.create = function(next, error, complete) {
|
|
476
476
|
return new SafeSubscriber(next, error, complete);
|
|
477
477
|
};
|
|
478
|
-
Subscriber$
|
|
478
|
+
Subscriber$1.prototype.next = function(value) {
|
|
479
479
|
if (this.isStopped) handleStoppedNotification(NotificationFactories_1.nextNotification(value), this);
|
|
480
480
|
else this._next(value);
|
|
481
481
|
};
|
|
482
|
-
Subscriber$
|
|
482
|
+
Subscriber$1.prototype.error = function(err) {
|
|
483
483
|
if (this.isStopped) handleStoppedNotification(NotificationFactories_1.errorNotification(err), this);
|
|
484
484
|
else {
|
|
485
485
|
this.isStopped = true;
|
|
486
486
|
this._error(err);
|
|
487
487
|
}
|
|
488
488
|
};
|
|
489
|
-
Subscriber$
|
|
489
|
+
Subscriber$1.prototype.complete = function() {
|
|
490
490
|
if (this.isStopped) handleStoppedNotification(NotificationFactories_1.COMPLETE_NOTIFICATION, this);
|
|
491
491
|
else {
|
|
492
492
|
this.isStopped = true;
|
|
493
493
|
this._complete();
|
|
494
494
|
}
|
|
495
495
|
};
|
|
496
|
-
Subscriber$
|
|
496
|
+
Subscriber$1.prototype.unsubscribe = function() {
|
|
497
497
|
if (!this.closed) {
|
|
498
498
|
this.isStopped = true;
|
|
499
499
|
_super.prototype.unsubscribe.call(this);
|
|
500
500
|
this.destination = null;
|
|
501
501
|
}
|
|
502
502
|
};
|
|
503
|
-
Subscriber$
|
|
503
|
+
Subscriber$1.prototype._next = function(value) {
|
|
504
504
|
this.destination.next(value);
|
|
505
505
|
};
|
|
506
|
-
Subscriber$
|
|
506
|
+
Subscriber$1.prototype._error = function(err) {
|
|
507
507
|
try {
|
|
508
508
|
this.destination.error(err);
|
|
509
509
|
} finally {
|
|
510
510
|
this.unsubscribe();
|
|
511
511
|
}
|
|
512
512
|
};
|
|
513
|
-
Subscriber$
|
|
513
|
+
Subscriber$1.prototype._complete = function() {
|
|
514
514
|
try {
|
|
515
515
|
this.destination.complete();
|
|
516
516
|
} finally {
|
|
517
517
|
this.unsubscribe();
|
|
518
518
|
}
|
|
519
519
|
};
|
|
520
|
-
return Subscriber$
|
|
520
|
+
return Subscriber$1;
|
|
521
521
|
}(Subscription_1$10.Subscription);
|
|
522
|
-
exports.Subscriber = Subscriber
|
|
522
|
+
exports.Subscriber = Subscriber;
|
|
523
523
|
var _bind = Function.prototype.bind;
|
|
524
524
|
function bind(fn, thisArg) {
|
|
525
525
|
return _bind.call(fn, thisArg);
|
|
@@ -583,7 +583,7 @@ var require_Subscriber = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
583
583
|
return _this;
|
|
584
584
|
}
|
|
585
585
|
return SafeSubscriber$1;
|
|
586
|
-
}(Subscriber
|
|
586
|
+
}(Subscriber);
|
|
587
587
|
exports.SafeSubscriber = SafeSubscriber;
|
|
588
588
|
function handleUnhandledError(error) {
|
|
589
589
|
if (config_1$2.config.useDeprecatedSynchronousErrorHandling) errorContext_1$2.captureError(error);
|
|
@@ -1129,9 +1129,9 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1129
1129
|
var ObjectUnsubscribedError_1$1 = require_ObjectUnsubscribedError();
|
|
1130
1130
|
var arrRemove_1$6 = require_arrRemove();
|
|
1131
1131
|
var errorContext_1 = require_errorContext();
|
|
1132
|
-
var Subject$
|
|
1133
|
-
__extends$13(Subject$
|
|
1134
|
-
function Subject$
|
|
1132
|
+
var Subject$1 = function(_super) {
|
|
1133
|
+
__extends$13(Subject$2, _super);
|
|
1134
|
+
function Subject$2() {
|
|
1135
1135
|
var _this = _super.call(this) || this;
|
|
1136
1136
|
_this.closed = false;
|
|
1137
1137
|
_this.currentObservers = null;
|
|
@@ -1141,15 +1141,15 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1141
1141
|
_this.thrownError = null;
|
|
1142
1142
|
return _this;
|
|
1143
1143
|
}
|
|
1144
|
-
Subject$
|
|
1144
|
+
Subject$2.prototype.lift = function(operator) {
|
|
1145
1145
|
var subject = new AnonymousSubject(this, this);
|
|
1146
1146
|
subject.operator = operator;
|
|
1147
1147
|
return subject;
|
|
1148
1148
|
};
|
|
1149
|
-
Subject$
|
|
1149
|
+
Subject$2.prototype._throwIfClosed = function() {
|
|
1150
1150
|
if (this.closed) throw new ObjectUnsubscribedError_1$1.ObjectUnsubscribedError();
|
|
1151
1151
|
};
|
|
1152
|
-
Subject$
|
|
1152
|
+
Subject$2.prototype.next = function(value) {
|
|
1153
1153
|
var _this = this;
|
|
1154
1154
|
errorContext_1.errorContext(function() {
|
|
1155
1155
|
var e_1, _a;
|
|
@@ -1170,7 +1170,7 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1170
1170
|
}
|
|
1171
1171
|
});
|
|
1172
1172
|
};
|
|
1173
|
-
Subject$
|
|
1173
|
+
Subject$2.prototype.error = function(err) {
|
|
1174
1174
|
var _this = this;
|
|
1175
1175
|
errorContext_1.errorContext(function() {
|
|
1176
1176
|
_this._throwIfClosed();
|
|
@@ -1182,7 +1182,7 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1182
1182
|
}
|
|
1183
1183
|
});
|
|
1184
1184
|
};
|
|
1185
|
-
Subject$
|
|
1185
|
+
Subject$2.prototype.complete = function() {
|
|
1186
1186
|
var _this = this;
|
|
1187
1187
|
errorContext_1.errorContext(function() {
|
|
1188
1188
|
_this._throwIfClosed();
|
|
@@ -1193,11 +1193,11 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1193
1193
|
}
|
|
1194
1194
|
});
|
|
1195
1195
|
};
|
|
1196
|
-
Subject$
|
|
1196
|
+
Subject$2.prototype.unsubscribe = function() {
|
|
1197
1197
|
this.isStopped = this.closed = true;
|
|
1198
1198
|
this.observers = this.currentObservers = null;
|
|
1199
1199
|
};
|
|
1200
|
-
Object.defineProperty(Subject$
|
|
1200
|
+
Object.defineProperty(Subject$2.prototype, "observed", {
|
|
1201
1201
|
get: function() {
|
|
1202
1202
|
var _a;
|
|
1203
1203
|
return ((_a = this.observers) === null || _a === void 0 ? void 0 : _a.length) > 0;
|
|
@@ -1205,16 +1205,16 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1205
1205
|
enumerable: false,
|
|
1206
1206
|
configurable: true
|
|
1207
1207
|
});
|
|
1208
|
-
Subject$
|
|
1208
|
+
Subject$2.prototype._trySubscribe = function(subscriber) {
|
|
1209
1209
|
this._throwIfClosed();
|
|
1210
1210
|
return _super.prototype._trySubscribe.call(this, subscriber);
|
|
1211
1211
|
};
|
|
1212
|
-
Subject$
|
|
1212
|
+
Subject$2.prototype._subscribe = function(subscriber) {
|
|
1213
1213
|
this._throwIfClosed();
|
|
1214
1214
|
this._checkFinalizedStatuses(subscriber);
|
|
1215
1215
|
return this._innerSubscribe(subscriber);
|
|
1216
1216
|
};
|
|
1217
|
-
Subject$
|
|
1217
|
+
Subject$2.prototype._innerSubscribe = function(subscriber) {
|
|
1218
1218
|
var _this = this;
|
|
1219
1219
|
var _a = this, hasError = _a.hasError, isStopped = _a.isStopped, observers = _a.observers;
|
|
1220
1220
|
if (hasError || isStopped) return Subscription_1$6.EMPTY_SUBSCRIPTION;
|
|
@@ -1225,22 +1225,22 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1225
1225
|
arrRemove_1$6.arrRemove(observers, subscriber);
|
|
1226
1226
|
});
|
|
1227
1227
|
};
|
|
1228
|
-
Subject$
|
|
1228
|
+
Subject$2.prototype._checkFinalizedStatuses = function(subscriber) {
|
|
1229
1229
|
var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, isStopped = _a.isStopped;
|
|
1230
1230
|
if (hasError) subscriber.error(thrownError);
|
|
1231
1231
|
else if (isStopped) subscriber.complete();
|
|
1232
1232
|
};
|
|
1233
|
-
Subject$
|
|
1233
|
+
Subject$2.prototype.asObservable = function() {
|
|
1234
1234
|
var observable = new Observable_1$24.Observable();
|
|
1235
1235
|
observable.source = this;
|
|
1236
1236
|
return observable;
|
|
1237
1237
|
};
|
|
1238
|
-
Subject$
|
|
1238
|
+
Subject$2.create = function(destination, source) {
|
|
1239
1239
|
return new AnonymousSubject(destination, source);
|
|
1240
1240
|
};
|
|
1241
|
-
return Subject$
|
|
1241
|
+
return Subject$2;
|
|
1242
1242
|
}(Observable_1$24.Observable);
|
|
1243
|
-
exports.Subject = Subject$
|
|
1243
|
+
exports.Subject = Subject$1;
|
|
1244
1244
|
var AnonymousSubject = function(_super) {
|
|
1245
1245
|
__extends$13(AnonymousSubject$1, _super);
|
|
1246
1246
|
function AnonymousSubject$1(destination, source) {
|
|
@@ -1266,7 +1266,7 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1266
1266
|
return (_b = (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber)) !== null && _b !== void 0 ? _b : Subscription_1$6.EMPTY_SUBSCRIPTION;
|
|
1267
1267
|
};
|
|
1268
1268
|
return AnonymousSubject$1;
|
|
1269
|
-
}(Subject$
|
|
1269
|
+
}(Subject$1);
|
|
1270
1270
|
exports.AnonymousSubject = AnonymousSubject;
|
|
1271
1271
|
}));
|
|
1272
1272
|
|
|
@@ -1293,37 +1293,37 @@ var require_BehaviorSubject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1293
1293
|
})();
|
|
1294
1294
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1295
1295
|
exports.BehaviorSubject = void 0;
|
|
1296
|
-
var BehaviorSubject$
|
|
1297
|
-
__extends$12(BehaviorSubject$
|
|
1298
|
-
function BehaviorSubject$
|
|
1296
|
+
var BehaviorSubject$1 = function(_super) {
|
|
1297
|
+
__extends$12(BehaviorSubject$2, _super);
|
|
1298
|
+
function BehaviorSubject$2(_value) {
|
|
1299
1299
|
var _this = _super.call(this) || this;
|
|
1300
1300
|
_this._value = _value;
|
|
1301
1301
|
return _this;
|
|
1302
1302
|
}
|
|
1303
|
-
Object.defineProperty(BehaviorSubject$
|
|
1303
|
+
Object.defineProperty(BehaviorSubject$2.prototype, "value", {
|
|
1304
1304
|
get: function() {
|
|
1305
1305
|
return this.getValue();
|
|
1306
1306
|
},
|
|
1307
1307
|
enumerable: false,
|
|
1308
1308
|
configurable: true
|
|
1309
1309
|
});
|
|
1310
|
-
BehaviorSubject$
|
|
1310
|
+
BehaviorSubject$2.prototype._subscribe = function(subscriber) {
|
|
1311
1311
|
var subscription = _super.prototype._subscribe.call(this, subscriber);
|
|
1312
1312
|
!subscription.closed && subscriber.next(this._value);
|
|
1313
1313
|
return subscription;
|
|
1314
1314
|
};
|
|
1315
|
-
BehaviorSubject$
|
|
1315
|
+
BehaviorSubject$2.prototype.getValue = function() {
|
|
1316
1316
|
var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, _value = _a._value;
|
|
1317
1317
|
if (hasError) throw thrownError;
|
|
1318
1318
|
this._throwIfClosed();
|
|
1319
1319
|
return _value;
|
|
1320
1320
|
};
|
|
1321
|
-
BehaviorSubject$
|
|
1321
|
+
BehaviorSubject$2.prototype.next = function(value) {
|
|
1322
1322
|
_super.prototype.next.call(this, this._value = value);
|
|
1323
1323
|
};
|
|
1324
|
-
return BehaviorSubject$
|
|
1324
|
+
return BehaviorSubject$2;
|
|
1325
1325
|
}(require_Subject().Subject);
|
|
1326
|
-
exports.BehaviorSubject = BehaviorSubject$
|
|
1326
|
+
exports.BehaviorSubject = BehaviorSubject$1;
|
|
1327
1327
|
}));
|
|
1328
1328
|
|
|
1329
1329
|
//#endregion
|
|
@@ -3095,13 +3095,13 @@ var require_of = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3095
3095
|
exports.of = void 0;
|
|
3096
3096
|
var args_1$12 = require_args();
|
|
3097
3097
|
var from_1$7 = require_from();
|
|
3098
|
-
function of$
|
|
3098
|
+
function of$2() {
|
|
3099
3099
|
var args = [];
|
|
3100
3100
|
for (var _i = 0; _i < arguments.length; _i++) args[_i] = arguments[_i];
|
|
3101
3101
|
var scheduler = args_1$12.popScheduler(args);
|
|
3102
3102
|
return from_1$7.from(args, scheduler);
|
|
3103
3103
|
}
|
|
3104
|
-
exports.of = of$
|
|
3104
|
+
exports.of = of$2;
|
|
3105
3105
|
}));
|
|
3106
3106
|
|
|
3107
3107
|
//#endregion
|
|
@@ -3250,7 +3250,7 @@ var require_firstValueFrom = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3250
3250
|
exports.firstValueFrom = void 0;
|
|
3251
3251
|
var EmptyError_1$5 = require_EmptyError();
|
|
3252
3252
|
var Subscriber_1$2 = require_Subscriber();
|
|
3253
|
-
function firstValueFrom$
|
|
3253
|
+
function firstValueFrom$7(source, config) {
|
|
3254
3254
|
var hasConfig = typeof config === "object";
|
|
3255
3255
|
return new Promise(function(resolve, reject) {
|
|
3256
3256
|
var subscriber = new Subscriber_1$2.SafeSubscriber({
|
|
@@ -3267,7 +3267,7 @@ var require_firstValueFrom = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3267
3267
|
source.subscribe(subscriber);
|
|
3268
3268
|
});
|
|
3269
3269
|
}
|
|
3270
|
-
exports.firstValueFrom = firstValueFrom$
|
|
3270
|
+
exports.firstValueFrom = firstValueFrom$7;
|
|
3271
3271
|
}));
|
|
3272
3272
|
|
|
3273
3273
|
//#endregion
|
|
@@ -3394,7 +3394,7 @@ var require_map = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3394
3394
|
exports.map = void 0;
|
|
3395
3395
|
var lift_1$64 = require_lift();
|
|
3396
3396
|
var OperatorSubscriber_1$54 = require_OperatorSubscriber();
|
|
3397
|
-
function map$
|
|
3397
|
+
function map$20(project, thisArg) {
|
|
3398
3398
|
return lift_1$64.operate(function(source, subscriber) {
|
|
3399
3399
|
var index = 0;
|
|
3400
3400
|
source.subscribe(OperatorSubscriber_1$54.createOperatorSubscriber(subscriber, function(value) {
|
|
@@ -3402,7 +3402,7 @@ var require_map = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3402
3402
|
}));
|
|
3403
3403
|
});
|
|
3404
3404
|
}
|
|
3405
|
-
exports.map = map$
|
|
3405
|
+
exports.map = map$20;
|
|
3406
3406
|
}));
|
|
3407
3407
|
|
|
3408
3408
|
//#endregion
|
|
@@ -4144,7 +4144,7 @@ var require_timer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
4144
4144
|
var async_1$11 = require_async();
|
|
4145
4145
|
var isScheduler_1 = require_isScheduler();
|
|
4146
4146
|
var isDate_1$1 = require_isDate();
|
|
4147
|
-
function timer$
|
|
4147
|
+
function timer$3(dueTime, intervalOrScheduler, scheduler) {
|
|
4148
4148
|
if (dueTime === void 0) dueTime = 0;
|
|
4149
4149
|
if (scheduler === void 0) scheduler = async_1$11.async;
|
|
4150
4150
|
var intervalDuration = -1;
|
|
@@ -4163,7 +4163,7 @@ var require_timer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
4163
4163
|
}, due);
|
|
4164
4164
|
});
|
|
4165
4165
|
}
|
|
4166
|
-
exports.timer = timer$
|
|
4166
|
+
exports.timer = timer$3;
|
|
4167
4167
|
}));
|
|
4168
4168
|
|
|
4169
4169
|
//#endregion
|
|
@@ -4173,13 +4173,13 @@ var require_interval = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
4173
4173
|
exports.interval = void 0;
|
|
4174
4174
|
var async_1$10 = require_async();
|
|
4175
4175
|
var timer_1$6 = require_timer();
|
|
4176
|
-
function interval$
|
|
4176
|
+
function interval$4(period, scheduler) {
|
|
4177
4177
|
if (period === void 0) period = 0;
|
|
4178
4178
|
if (scheduler === void 0) scheduler = async_1$10.asyncScheduler;
|
|
4179
4179
|
if (period < 0) period = 0;
|
|
4180
4180
|
return timer_1$6.timer(period, period, scheduler);
|
|
4181
4181
|
}
|
|
4182
|
-
exports.interval = interval$
|
|
4182
|
+
exports.interval = interval$4;
|
|
4183
4183
|
}));
|
|
4184
4184
|
|
|
4185
4185
|
//#endregion
|
|
@@ -4331,13 +4331,13 @@ var require_race$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
4331
4331
|
var innerFrom_1$28 = require_innerFrom();
|
|
4332
4332
|
var argsOrArgArray_1$4 = require_argsOrArgArray();
|
|
4333
4333
|
var OperatorSubscriber_1$48 = require_OperatorSubscriber();
|
|
4334
|
-
function race$
|
|
4334
|
+
function race$5() {
|
|
4335
4335
|
var sources = [];
|
|
4336
4336
|
for (var _i = 0; _i < arguments.length; _i++) sources[_i] = arguments[_i];
|
|
4337
4337
|
sources = argsOrArgArray_1$4.argsOrArgArray(sources);
|
|
4338
4338
|
return sources.length === 1 ? innerFrom_1$28.innerFrom(sources[0]) : new Observable_1$6.Observable(raceInit(sources));
|
|
4339
4339
|
}
|
|
4340
|
-
exports.race = race$
|
|
4340
|
+
exports.race = race$5;
|
|
4341
4341
|
function raceInit(sources) {
|
|
4342
4342
|
return function(subscriber) {
|
|
4343
4343
|
var subscriptions = [];
|
|
@@ -5335,7 +5335,7 @@ var require_take = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5335
5335
|
var empty_1$3 = require_empty();
|
|
5336
5336
|
var lift_1$46 = require_lift();
|
|
5337
5337
|
var OperatorSubscriber_1$35 = require_OperatorSubscriber();
|
|
5338
|
-
function take$
|
|
5338
|
+
function take$9(count$1) {
|
|
5339
5339
|
return count$1 <= 0 ? function() {
|
|
5340
5340
|
return empty_1$3.EMPTY;
|
|
5341
5341
|
} : lift_1$46.operate(function(source, subscriber) {
|
|
@@ -5348,7 +5348,7 @@ var require_take = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5348
5348
|
}));
|
|
5349
5349
|
});
|
|
5350
5350
|
}
|
|
5351
|
-
exports.take = take$
|
|
5351
|
+
exports.take = take$9;
|
|
5352
5352
|
}));
|
|
5353
5353
|
|
|
5354
5354
|
//#endregion
|
|
@@ -5474,7 +5474,7 @@ var require_distinctUntilChanged = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5474
5474
|
var identity_1$10 = require_identity();
|
|
5475
5475
|
var lift_1$42 = require_lift();
|
|
5476
5476
|
var OperatorSubscriber_1$31 = require_OperatorSubscriber();
|
|
5477
|
-
function distinctUntilChanged$
|
|
5477
|
+
function distinctUntilChanged$9(comparator, keySelector) {
|
|
5478
5478
|
if (keySelector === void 0) keySelector = identity_1$10.identity;
|
|
5479
5479
|
comparator = comparator !== null && comparator !== void 0 ? comparator : defaultCompare;
|
|
5480
5480
|
return lift_1$42.operate(function(source, subscriber) {
|
|
@@ -5490,7 +5490,7 @@ var require_distinctUntilChanged = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5490
5490
|
}));
|
|
5491
5491
|
});
|
|
5492
5492
|
}
|
|
5493
|
-
exports.distinctUntilChanged = distinctUntilChanged$
|
|
5493
|
+
exports.distinctUntilChanged = distinctUntilChanged$9;
|
|
5494
5494
|
function defaultCompare(a, b) {
|
|
5495
5495
|
return a === b;
|
|
5496
5496
|
}
|
|
@@ -7186,17 +7186,17 @@ var require_timeInterval = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7186
7186
|
var last$2 = scheduler.now();
|
|
7187
7187
|
source.subscribe(OperatorSubscriber_1$6.createOperatorSubscriber(subscriber, function(value) {
|
|
7188
7188
|
var now = scheduler.now();
|
|
7189
|
-
var interval$
|
|
7189
|
+
var interval$5 = now - last$2;
|
|
7190
7190
|
last$2 = now;
|
|
7191
|
-
subscriber.next(new TimeInterval(value, interval$
|
|
7191
|
+
subscriber.next(new TimeInterval(value, interval$5));
|
|
7192
7192
|
}));
|
|
7193
7193
|
});
|
|
7194
7194
|
}
|
|
7195
7195
|
exports.timeInterval = timeInterval;
|
|
7196
7196
|
var TimeInterval = function() {
|
|
7197
|
-
function TimeInterval$1(value, interval$
|
|
7197
|
+
function TimeInterval$1(value, interval$5) {
|
|
7198
7198
|
this.value = value;
|
|
7199
|
-
this.interval = interval$
|
|
7199
|
+
this.interval = interval$5;
|
|
7200
7200
|
}
|
|
7201
7201
|
return TimeInterval$1;
|
|
7202
7202
|
}();
|
|
@@ -8937,12 +8937,12 @@ var require_cjs = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
8937
8937
|
|
|
8938
8938
|
//#endregion
|
|
8939
8939
|
//#region src/behaviors/Destroyable.ts
|
|
8940
|
-
var import_cjs$
|
|
8940
|
+
var import_cjs$30 = require_cjs();
|
|
8941
8941
|
var Destroyable = class {
|
|
8942
8942
|
constructor() {
|
|
8943
8943
|
this.subscriptions = [];
|
|
8944
8944
|
this.subjects = [];
|
|
8945
|
-
this._destroyed$ = new import_cjs$
|
|
8945
|
+
this._destroyed$ = new import_cjs$30.Subject();
|
|
8946
8946
|
}
|
|
8947
8947
|
destroy() {
|
|
8948
8948
|
this._observableCache?.clear();
|
|
@@ -8978,7 +8978,7 @@ var Destroyable = class {
|
|
|
8978
8978
|
this._observableCache ??= /* @__PURE__ */ new Map();
|
|
8979
8979
|
let cached = this._observableCache.get(publicKey);
|
|
8980
8980
|
if (!cached) {
|
|
8981
|
-
cached = factory().pipe((0, import_cjs$
|
|
8981
|
+
cached = factory().pipe((0, import_cjs$30.observeOn)(import_cjs$30.asapScheduler));
|
|
8982
8982
|
this._observableCache.set(publicKey, cached);
|
|
8983
8983
|
}
|
|
8984
8984
|
return cached;
|
|
@@ -8992,24 +8992,24 @@ var Destroyable = class {
|
|
|
8992
8992
|
* Do NOT use for observables consumed internally by the SDK.
|
|
8993
8993
|
*/
|
|
8994
8994
|
deferEmission(observable) {
|
|
8995
|
-
return observable.pipe((0, import_cjs$
|
|
8995
|
+
return observable.pipe((0, import_cjs$30.observeOn)(import_cjs$30.asapScheduler));
|
|
8996
8996
|
}
|
|
8997
8997
|
subscribeTo(observable, observerOrNext) {
|
|
8998
8998
|
const subscription = observable.subscribe(observerOrNext);
|
|
8999
8999
|
this.subscriptions.push(subscription);
|
|
9000
9000
|
}
|
|
9001
9001
|
createSubject() {
|
|
9002
|
-
const subject = new import_cjs$
|
|
9002
|
+
const subject = new import_cjs$30.Subject();
|
|
9003
9003
|
this.subjects.push(subject);
|
|
9004
9004
|
return subject;
|
|
9005
9005
|
}
|
|
9006
9006
|
createReplaySubject(bufferSize, windowTime$1) {
|
|
9007
|
-
const subject = new import_cjs$
|
|
9007
|
+
const subject = new import_cjs$30.ReplaySubject(bufferSize, windowTime$1);
|
|
9008
9008
|
this.subjects.push(subject);
|
|
9009
9009
|
return subject;
|
|
9010
9010
|
}
|
|
9011
9011
|
createBehaviorSubject(initialValue) {
|
|
9012
|
-
const subject = new import_cjs$
|
|
9012
|
+
const subject = new import_cjs$30.BehaviorSubject(initialValue);
|
|
9013
9013
|
this.subjects.push(subject);
|
|
9014
9014
|
return subject;
|
|
9015
9015
|
}
|
|
@@ -9470,9 +9470,9 @@ var require_loglevel = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
9470
9470
|
defaultLogger$1 = new Logger();
|
|
9471
9471
|
defaultLogger$1.getLogger = function getLogger$1(name) {
|
|
9472
9472
|
if (typeof name !== "symbol" && typeof name !== "string" || name === "") throw new TypeError("You must supply a name when creating a logger.");
|
|
9473
|
-
var logger$
|
|
9474
|
-
if (!logger$
|
|
9475
|
-
return logger$
|
|
9473
|
+
var logger$32 = _loggersByName[name];
|
|
9474
|
+
if (!logger$32) logger$32 = _loggersByName[name] = new Logger(name, defaultLogger$1.methodFactory);
|
|
9475
|
+
return logger$32;
|
|
9476
9476
|
};
|
|
9477
9477
|
var _log = typeof window !== undefinedType ? window.log : void 0;
|
|
9478
9478
|
defaultLogger$1.noConflict = function() {
|
|
@@ -9508,8 +9508,8 @@ const defaultLoggerLevel = defaultLogger.levels.WARN;
|
|
|
9508
9508
|
defaultLogger.setLevel(defaultLoggerLevel);
|
|
9509
9509
|
let userLogger = null;
|
|
9510
9510
|
/** Replace the built-in logger with a custom implementation. Pass `null` to restore defaults. */
|
|
9511
|
-
const setLogger = (logger$
|
|
9512
|
-
userLogger = logger$
|
|
9511
|
+
const setLogger = (logger$32) => {
|
|
9512
|
+
userLogger = logger$32;
|
|
9513
9513
|
};
|
|
9514
9514
|
let debugOptions = {};
|
|
9515
9515
|
/** Configure debug options (e.g., `{ logWsTraffic: true }`). */
|
|
@@ -9548,13 +9548,13 @@ const wsTraffic = (options) => {
|
|
|
9548
9548
|
loggerInstance.debug(`[WebSocket] ${options.type.toUpperCase()}: non-JSON message`);
|
|
9549
9549
|
return;
|
|
9550
9550
|
}
|
|
9551
|
-
else payload = options
|
|
9551
|
+
else ({payload} = options);
|
|
9552
9552
|
const msg = shouldStringify(payload) ? JSON.stringify(payload, null, 2) : payload;
|
|
9553
9553
|
loggerInstance.debug(`${options.type.toUpperCase()}: \n`, msg, "\n");
|
|
9554
9554
|
};
|
|
9555
9555
|
const getLogger = () => {
|
|
9556
|
-
const logger$
|
|
9557
|
-
return new Proxy(logger$
|
|
9556
|
+
const logger$32 = getLoggerInstance();
|
|
9557
|
+
return new Proxy(logger$32, { get(_target, prop, _receiver) {
|
|
9558
9558
|
if (prop === "wsTraffic") return wsTraffic;
|
|
9559
9559
|
const instance = getLoggerInstance();
|
|
9560
9560
|
const value = Reflect.get(instance, prop);
|
|
@@ -9606,8 +9606,7 @@ const asyncRetry = async ({ asyncCallable, maxRetries: retries = DEFAULT_MAX_RET
|
|
|
9606
9606
|
|
|
9607
9607
|
//#endregion
|
|
9608
9608
|
//#region src/controllers/HTTPRequestController.ts
|
|
9609
|
-
|
|
9610
|
-
const logger$29 = getLogger();
|
|
9609
|
+
const logger$31 = getLogger();
|
|
9611
9610
|
const GET_PARAMS = {
|
|
9612
9611
|
method: "GET",
|
|
9613
9612
|
headers: { Accept: "application/json" }
|
|
@@ -9619,7 +9618,7 @@ const POST_PARAMS = {
|
|
|
9619
9618
|
"Content-Type": "application/json"
|
|
9620
9619
|
}
|
|
9621
9620
|
};
|
|
9622
|
-
var HTTPRequestController = class HTTPRequestController {
|
|
9621
|
+
var HTTPRequestController = class HTTPRequestController extends Destroyable {
|
|
9623
9622
|
static {
|
|
9624
9623
|
this.defaultMaxRetries = 3;
|
|
9625
9624
|
}
|
|
@@ -9640,11 +9639,12 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9640
9639
|
]);
|
|
9641
9640
|
}
|
|
9642
9641
|
constructor(baseURL, getCredential, options = {}) {
|
|
9642
|
+
super();
|
|
9643
9643
|
this.baseURL = baseURL;
|
|
9644
9644
|
this.getCredential = getCredential;
|
|
9645
|
-
this._responses$ =
|
|
9646
|
-
this._errors$ =
|
|
9647
|
-
this._status$ =
|
|
9645
|
+
this._responses$ = this.createSubject();
|
|
9646
|
+
this._errors$ = this.createSubject();
|
|
9647
|
+
this._status$ = this.createBehaviorSubject("idle");
|
|
9648
9648
|
this.maxRetries = options.maxRetries ?? HTTPRequestController.defaultMaxRetries;
|
|
9649
9649
|
this.retryDelayMin = options.retryDelayMin ?? HTTPRequestController.defaultRetryDelayMinMs;
|
|
9650
9650
|
this.retryDelayMax = options.retryDelayMax ?? HTTPRequestController.defaultRetryDelayMaxMs;
|
|
@@ -9670,7 +9670,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9670
9670
|
this._responses$.next(response);
|
|
9671
9671
|
return response;
|
|
9672
9672
|
} catch (error) {
|
|
9673
|
-
logger$
|
|
9673
|
+
logger$31.error("[HTTPRequestController] Request error:", error);
|
|
9674
9674
|
this._status$.next("error");
|
|
9675
9675
|
const err = error instanceof Error ? error : new Error("HTTP request failed", { cause: error });
|
|
9676
9676
|
this._errors$.next(err);
|
|
@@ -9697,7 +9697,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9697
9697
|
const url = this.buildURL(request.url);
|
|
9698
9698
|
const headers = this.buildHeaders(request.headers);
|
|
9699
9699
|
const timeout$5 = request.timeout ?? this.requestTimeout;
|
|
9700
|
-
logger$
|
|
9700
|
+
logger$31.debug("[HTTPRequestController] Executing request:", {
|
|
9701
9701
|
method: request.method,
|
|
9702
9702
|
url,
|
|
9703
9703
|
headers: Object.keys(headers).reduce((acc, key) => {
|
|
@@ -9717,7 +9717,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9717
9717
|
});
|
|
9718
9718
|
clearTimeout(timeoutId);
|
|
9719
9719
|
const httpResponse = await this.convertResponse(response);
|
|
9720
|
-
logger$
|
|
9720
|
+
logger$31.debug("[HTTPRequestController] Response received:", {
|
|
9721
9721
|
status: response.status,
|
|
9722
9722
|
statusText: response.statusText,
|
|
9723
9723
|
headers: [...response.headers.entries()],
|
|
@@ -9727,7 +9727,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9727
9727
|
} catch (error) {
|
|
9728
9728
|
clearTimeout(timeoutId);
|
|
9729
9729
|
if (error instanceof Error && error.name === "AbortError") throw new RequestTimeoutError(`Request timeout after ${timeout$5}ms`, { cause: error });
|
|
9730
|
-
logger$
|
|
9730
|
+
logger$31.error("[HTTPRequestController] Request failed:", error);
|
|
9731
9731
|
throw error;
|
|
9732
9732
|
}
|
|
9733
9733
|
}
|
|
@@ -9741,8 +9741,8 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9741
9741
|
const credential = this.getCredential();
|
|
9742
9742
|
if (credential.token) {
|
|
9743
9743
|
headers.Authorization = `Bearer ${credential.token}`;
|
|
9744
|
-
logger$
|
|
9745
|
-
} else logger$
|
|
9744
|
+
logger$31.debug("[HTTPRequestController] Using Bearer token auth, token length:", credential.token.length);
|
|
9745
|
+
} else logger$31.warn("[HTTPRequestController] No credentials available for authentication");
|
|
9746
9746
|
return headers;
|
|
9747
9747
|
}
|
|
9748
9748
|
/**
|
|
@@ -9954,6 +9954,18 @@ const DEFAULT_ICE_DISCONNECTED_GRACE_PERIOD_MS = 3e3;
|
|
|
9954
9954
|
const DEFAULT_ICE_RESTART_TIMEOUT_MS$1 = 5e3;
|
|
9955
9955
|
/** Maximum recovery attempts before emitting 'max_attempts_reached'. */
|
|
9956
9956
|
const DEFAULT_MAX_RECOVERY_ATTEMPTS = 3;
|
|
9957
|
+
/** Upper bound in ms for waiting on iceGatheringState === 'complete' after an ICE restart. */
|
|
9958
|
+
const ICE_GATHERING_COMPLETE_TIMEOUT_MS = 1e4;
|
|
9959
|
+
/** Upper bound in ms for waiting on RTCPeerConnection.connectionState === 'connected' after a recovery ICE restart. */
|
|
9960
|
+
const PEER_CONNECTION_RECOVERY_WAIT_MS = 5e3;
|
|
9961
|
+
/** Polling interval in ms while waiting for RTCPeerConnection.connectionState to transition. */
|
|
9962
|
+
const PEER_CONNECTION_RECOVERY_POLL_MS = 100;
|
|
9963
|
+
/** Polling interval for LocalAudioPipeline.level$ (ms). ~30fps is smooth for meters. */
|
|
9964
|
+
const AUDIO_LEVEL_POLL_INTERVAL_MS = 33;
|
|
9965
|
+
/** RMS level threshold (0..1) above which the local participant is considered speaking. */
|
|
9966
|
+
const VAD_THRESHOLD = .03;
|
|
9967
|
+
/** Hold window in ms below the threshold before speaking$ flips back to false. */
|
|
9968
|
+
const VAD_HOLD_MS = 250;
|
|
9957
9969
|
/** Whether to persist device selections to storage by default. */
|
|
9958
9970
|
const DEFAULT_PERSIST_DEVICE_SELECTION = true;
|
|
9959
9971
|
/** Whether to auto-apply device changes to active calls by default. */
|
|
@@ -10002,7 +10014,7 @@ function fromMsToSec(milliseconds) {
|
|
|
10002
10014
|
|
|
10003
10015
|
//#endregion
|
|
10004
10016
|
//#region src/containers/PreferencesContainer.ts
|
|
10005
|
-
const logger$
|
|
10017
|
+
const logger$30 = getLogger();
|
|
10006
10018
|
var PreferencesContainer = class PreferencesContainer {
|
|
10007
10019
|
static get instance() {
|
|
10008
10020
|
this._instance ??= new PreferencesContainer();
|
|
@@ -10664,7 +10676,7 @@ var ClientPreferences = class {
|
|
|
10664
10676
|
if (!this._storage) return;
|
|
10665
10677
|
const data = collectStoredPreferences();
|
|
10666
10678
|
this._storage.setItem(PREFERENCES_STORAGE_KEY, data, "local").catch((error) => {
|
|
10667
|
-
logger$
|
|
10679
|
+
logger$30.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);
|
|
10668
10680
|
});
|
|
10669
10681
|
}
|
|
10670
10682
|
/** Loads preferences from storage and applies them to the container. */
|
|
@@ -10673,7 +10685,7 @@ var ClientPreferences = class {
|
|
|
10673
10685
|
this._storage.getItem(PREFERENCES_STORAGE_KEY, "local").then((stored) => {
|
|
10674
10686
|
if (stored) applyStoredPreferences(stored);
|
|
10675
10687
|
}).catch((error) => {
|
|
10676
|
-
logger$
|
|
10688
|
+
logger$30.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);
|
|
10677
10689
|
});
|
|
10678
10690
|
}
|
|
10679
10691
|
};
|
|
@@ -10694,8 +10706,8 @@ function toError(value) {
|
|
|
10694
10706
|
|
|
10695
10707
|
//#endregion
|
|
10696
10708
|
//#region src/controllers/NavigatorDeviceController.ts
|
|
10697
|
-
var import_cjs$
|
|
10698
|
-
const logger$
|
|
10709
|
+
var import_cjs$29 = require_cjs();
|
|
10710
|
+
const logger$29 = getLogger();
|
|
10699
10711
|
/** Maps a device kind to its storage key. */
|
|
10700
10712
|
const DEVICE_STORAGE_KEYS = {
|
|
10701
10713
|
audioinput: DEVICE_STORAGE_KEY_AUDIO_INPUT,
|
|
@@ -10717,7 +10729,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10717
10729
|
super();
|
|
10718
10730
|
this.webRTCApiProvider = webRTCApiProvider;
|
|
10719
10731
|
this.deviceChangeHandler = () => {
|
|
10720
|
-
logger$
|
|
10732
|
+
logger$29.debug("[DeviceController] Device change detected");
|
|
10721
10733
|
this.enumerateDevices();
|
|
10722
10734
|
};
|
|
10723
10735
|
this._devicesState$ = this.createBehaviorSubject(initialDevicesState);
|
|
@@ -10754,17 +10766,17 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10754
10766
|
return {};
|
|
10755
10767
|
}
|
|
10756
10768
|
get errors$() {
|
|
10757
|
-
return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$
|
|
10769
|
+
return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10758
10770
|
}
|
|
10759
10771
|
/** Observable that emits when the SDK auto-switches a device. */
|
|
10760
10772
|
get deviceRecovered$() {
|
|
10761
|
-
return this._deviceRecovered$.asObservable().pipe((0, import_cjs$
|
|
10773
|
+
return this._deviceRecovered$.asObservable().pipe((0, import_cjs$29.takeUntil)(this.destroyed$));
|
|
10762
10774
|
}
|
|
10763
10775
|
get videoInputDisabled$() {
|
|
10764
|
-
return this.cachedObservable("videoInputDisabled$", () => this._videoInputDisabled$.asObservable().pipe((0, import_cjs$
|
|
10776
|
+
return this.cachedObservable("videoInputDisabled$", () => this._videoInputDisabled$.asObservable().pipe((0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10765
10777
|
}
|
|
10766
10778
|
get audioInputDisabled$() {
|
|
10767
|
-
return this.cachedObservable("audioInputDisabled$", () => this._audioInputDisabled$.asObservable().pipe((0, import_cjs$
|
|
10779
|
+
return this.cachedObservable("audioInputDisabled$", () => this._audioInputDisabled$.asObservable().pipe((0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10768
10780
|
}
|
|
10769
10781
|
get videoInputDisabled() {
|
|
10770
10782
|
return this._videoInputDisabled$.value;
|
|
@@ -10773,22 +10785,22 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10773
10785
|
return this._audioInputDisabled$.value;
|
|
10774
10786
|
}
|
|
10775
10787
|
get audioInputDevices$() {
|
|
10776
|
-
return this.cachedObservable("audioInputDevices$", () => this._devicesState$.pipe((0, import_cjs$
|
|
10788
|
+
return this.cachedObservable("audioInputDevices$", () => this._devicesState$.pipe((0, import_cjs$29.map)((state) => state.audioinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10777
10789
|
}
|
|
10778
10790
|
get audioOutputDevices$() {
|
|
10779
|
-
return this.cachedObservable("audioOutputDevices$", () => this._devicesState$.pipe((0, import_cjs$
|
|
10791
|
+
return this.cachedObservable("audioOutputDevices$", () => this._devicesState$.pipe((0, import_cjs$29.map)((state) => state.audiooutput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10780
10792
|
}
|
|
10781
10793
|
get videoInputDevices$() {
|
|
10782
|
-
return this.cachedObservable("videoInputDevices$", () => this._devicesState$.pipe((0, import_cjs$
|
|
10794
|
+
return this.cachedObservable("videoInputDevices$", () => this._devicesState$.pipe((0, import_cjs$29.map)((state) => state.videoinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10783
10795
|
}
|
|
10784
10796
|
get selectedAudioInputDevice$() {
|
|
10785
|
-
return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$
|
|
10797
|
+
return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.audioinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$29.debug("[DeviceController] Selected audio input device changed:", info))));
|
|
10786
10798
|
}
|
|
10787
10799
|
get selectedAudioOutputDevice$() {
|
|
10788
|
-
return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$
|
|
10800
|
+
return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.audiooutput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$29.debug("[DeviceController] Selected audio output device changed:", info))));
|
|
10789
10801
|
}
|
|
10790
10802
|
get selectedVideoInputDevice$() {
|
|
10791
|
-
return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$
|
|
10803
|
+
return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.videoinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$29.debug("[DeviceController] Selected video input device changed:", info))));
|
|
10792
10804
|
}
|
|
10793
10805
|
get selectedAudioInputDevice() {
|
|
10794
10806
|
if (this._audioInputDisabled$.value) return null;
|
|
@@ -10863,7 +10875,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10863
10875
|
if (device) this.persistDeviceSelection("audioinput", device);
|
|
10864
10876
|
}
|
|
10865
10877
|
selectVideoInputDevice(device) {
|
|
10866
|
-
logger$
|
|
10878
|
+
logger$29.debug("[DeviceController] Setting selected video input device:", device);
|
|
10867
10879
|
if (this._videoInputDisabled$.value && device) this._videoInputDisabled$.next(false);
|
|
10868
10880
|
const previous = this._selectedDevicesState$.value.videoinput;
|
|
10869
10881
|
if (previous && previous.deviceId !== device?.deviceId) this._deviceHistory.push("videoinput", previous);
|
|
@@ -10884,7 +10896,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10884
10896
|
}
|
|
10885
10897
|
init() {
|
|
10886
10898
|
this.loadPersistedDevices();
|
|
10887
|
-
this.subscribeTo(this._devicesState$.pipe((0, import_cjs$
|
|
10899
|
+
this.subscribeTo(this._devicesState$.pipe((0, import_cjs$29.debounceTime)(PreferencesContainer.instance.deviceDebounceTime)), (devicesState) => {
|
|
10888
10900
|
const currentSelected = this._selectedDevicesState$.value;
|
|
10889
10901
|
const newAudioInput = this._audioInputDisabled$.value ? null : this.resolveDevice("audioinput", devicesState.audioinput, currentSelected.audioinput, PreferencesContainer.instance.preferredAudioInput);
|
|
10890
10902
|
const newAudioOutput = this.resolveDevice("audiooutput", devicesState.audiooutput, currentSelected.audiooutput, PreferencesContainer.instance.preferredAudioOutput);
|
|
@@ -10920,7 +10932,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10920
10932
|
}
|
|
10921
10933
|
const fromHistory = this._deviceHistory.findInHistory(kind, devices);
|
|
10922
10934
|
if (fromHistory) {
|
|
10923
|
-
logger$
|
|
10935
|
+
logger$29.debug(`[DeviceController] Device disappeared, falling back to history: ${fromHistory.label}`);
|
|
10924
10936
|
this.emitDeviceRecovered(kind, selected, fromHistory, "device_disconnected");
|
|
10925
10937
|
return fromHistory;
|
|
10926
10938
|
}
|
|
@@ -10973,7 +10985,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10973
10985
|
try {
|
|
10974
10986
|
await this._storageManager.setItem(DEVICE_STORAGE_KEYS[kind], stored, "local");
|
|
10975
10987
|
} catch (error) {
|
|
10976
|
-
logger$
|
|
10988
|
+
logger$29.error(`[DeviceController] Failed to persist device selection for ${kind}:`, error);
|
|
10977
10989
|
}
|
|
10978
10990
|
}
|
|
10979
10991
|
async loadPersistedDevices() {
|
|
@@ -10989,7 +11001,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10989
11001
|
[kind]: stored
|
|
10990
11002
|
};
|
|
10991
11003
|
} catch (error) {
|
|
10992
|
-
logger$
|
|
11004
|
+
logger$29.error(`[DeviceController] Failed to load persisted device for ${kind}:`, error);
|
|
10993
11005
|
}
|
|
10994
11006
|
}
|
|
10995
11007
|
/** Clears device history, persisted selections, and re-enumerates devices. */
|
|
@@ -11006,8 +11018,8 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
11006
11018
|
enableDeviceMonitoring() {
|
|
11007
11019
|
this.disableDeviceMonitoring();
|
|
11008
11020
|
this.webRTCApiProvider.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
|
|
11009
|
-
if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$
|
|
11010
|
-
logger$
|
|
11021
|
+
if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$29.interval)(PreferencesContainer.instance.devicePollingInterval).subscribe(() => {
|
|
11022
|
+
logger$29.debug("[DeviceController] Polling devices due to interval");
|
|
11011
11023
|
this.enumerateDevices();
|
|
11012
11024
|
});
|
|
11013
11025
|
this.enumerateDevices();
|
|
@@ -11033,13 +11045,13 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
11033
11045
|
videoinput: []
|
|
11034
11046
|
});
|
|
11035
11047
|
this._devicesState$.next(devicesByKind);
|
|
11036
|
-
logger$
|
|
11048
|
+
logger$29.debug("[DeviceController] Devices enumerated:", {
|
|
11037
11049
|
audioInputs: devicesByKind.audioinput.length,
|
|
11038
11050
|
audioOutputs: devicesByKind.audiooutput.length,
|
|
11039
11051
|
videoInputs: devicesByKind.videoinput.length
|
|
11040
11052
|
});
|
|
11041
11053
|
} catch (error) {
|
|
11042
|
-
logger$
|
|
11054
|
+
logger$29.error("[DeviceController] Failed to enumerate devices:", error);
|
|
11043
11055
|
this._errors$.next(toError(error));
|
|
11044
11056
|
}
|
|
11045
11057
|
}
|
|
@@ -11055,7 +11067,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
11055
11067
|
stream.getTracks().forEach((t) => t.stop());
|
|
11056
11068
|
return capabilities;
|
|
11057
11069
|
} catch (error) {
|
|
11058
|
-
logger$
|
|
11070
|
+
logger$29.error("[DeviceController] Failed to get device capabilities:", error);
|
|
11059
11071
|
this._errors$.next(toError(error));
|
|
11060
11072
|
throw error;
|
|
11061
11073
|
}
|
|
@@ -11207,15 +11219,15 @@ var DependencyContainer = class {
|
|
|
11207
11219
|
this._baseURL = this.apiHost;
|
|
11208
11220
|
this._credential = {};
|
|
11209
11221
|
}
|
|
11210
|
-
get
|
|
11211
|
-
return this.
|
|
11222
|
+
get userId() {
|
|
11223
|
+
return this.user.id;
|
|
11212
11224
|
}
|
|
11213
|
-
get
|
|
11214
|
-
if (!this.
|
|
11215
|
-
return this.
|
|
11225
|
+
get user() {
|
|
11226
|
+
if (!this._user) throw new DependencyError("User");
|
|
11227
|
+
return this._user;
|
|
11216
11228
|
}
|
|
11217
|
-
set
|
|
11218
|
-
this.
|
|
11229
|
+
set user(user) {
|
|
11230
|
+
this._user = user;
|
|
11219
11231
|
}
|
|
11220
11232
|
get storage() {
|
|
11221
11233
|
if (!this._storageManager) {
|
|
@@ -11261,16 +11273,16 @@ var DependencyContainer = class {
|
|
|
11261
11273
|
this._deviceController = void 0;
|
|
11262
11274
|
}
|
|
11263
11275
|
get authorizationStateKey() {
|
|
11264
|
-
return `sw:${this.
|
|
11276
|
+
return `sw:${this.userId}:as`;
|
|
11265
11277
|
}
|
|
11266
11278
|
get protocolKey() {
|
|
11267
|
-
return `sw:${this.
|
|
11279
|
+
return `sw:${this.userId}:pt`;
|
|
11268
11280
|
}
|
|
11269
11281
|
get attachedCallsKey() {
|
|
11270
|
-
return `sw:${this.
|
|
11282
|
+
return `sw:${this.userId}:att`;
|
|
11271
11283
|
}
|
|
11272
|
-
|
|
11273
|
-
return this.
|
|
11284
|
+
getUserFromAddressId() {
|
|
11285
|
+
return this.user.addresses[0]?.id ?? "";
|
|
11274
11286
|
}
|
|
11275
11287
|
set baseURL(baseURL) {
|
|
11276
11288
|
this._baseURL = baseURL;
|
|
@@ -11306,7 +11318,7 @@ var DependencyContainer = class {
|
|
|
11306
11318
|
|
|
11307
11319
|
//#endregion
|
|
11308
11320
|
//#region src/controllers/CryptoController.ts
|
|
11309
|
-
const logger$
|
|
11321
|
+
const logger$28 = getLogger();
|
|
11310
11322
|
const DPOP_DB_NAME = "sw-dpop";
|
|
11311
11323
|
const DPOP_DB_VERSION = 1;
|
|
11312
11324
|
const DPOP_STORE_NAME = "keys";
|
|
@@ -11365,7 +11377,7 @@ async function loadKeyPairFromDB() {
|
|
|
11365
11377
|
tx.oncomplete = () => db.close();
|
|
11366
11378
|
});
|
|
11367
11379
|
} catch (error) {
|
|
11368
|
-
logger$
|
|
11380
|
+
logger$28.warn("[DPoP] Failed to load key pair from IndexedDB:", error);
|
|
11369
11381
|
return null;
|
|
11370
11382
|
}
|
|
11371
11383
|
}
|
|
@@ -11385,7 +11397,7 @@ async function saveKeyPairToDB(keyPair) {
|
|
|
11385
11397
|
};
|
|
11386
11398
|
});
|
|
11387
11399
|
} catch (error) {
|
|
11388
|
-
logger$
|
|
11400
|
+
logger$28.warn("[DPoP] Failed to save key pair to IndexedDB:", error);
|
|
11389
11401
|
}
|
|
11390
11402
|
}
|
|
11391
11403
|
async function deleteKeyPairFromDB() {
|
|
@@ -11404,7 +11416,7 @@ async function deleteKeyPairFromDB() {
|
|
|
11404
11416
|
};
|
|
11405
11417
|
});
|
|
11406
11418
|
} catch (error) {
|
|
11407
|
-
logger$
|
|
11419
|
+
logger$28.warn("[DPoP] Failed to delete key pair from IndexedDB:", error);
|
|
11408
11420
|
}
|
|
11409
11421
|
}
|
|
11410
11422
|
/**
|
|
@@ -11464,13 +11476,13 @@ var CryptoController = class {
|
|
|
11464
11476
|
this._publicJwk = await crypto.subtle.exportKey("jwk", stored.publicKey);
|
|
11465
11477
|
this._fingerprint = await computeJwkThumbprint(this._publicJwk);
|
|
11466
11478
|
this._initialized = true;
|
|
11467
|
-
logger$
|
|
11479
|
+
logger$28.debug("[DPoP] Key pair restored from IndexedDB, fingerprint:", this._fingerprint);
|
|
11468
11480
|
return this._fingerprint;
|
|
11469
11481
|
} catch (error) {
|
|
11470
|
-
logger$
|
|
11482
|
+
logger$28.warn("[DPoP] Stored key pair unusable, generating new one:", error);
|
|
11471
11483
|
await deleteKeyPairFromDB();
|
|
11472
11484
|
}
|
|
11473
|
-
logger$
|
|
11485
|
+
logger$28.debug("[DPoP] Generating RSA key pair");
|
|
11474
11486
|
this._keyPair = await crypto.subtle.generateKey({
|
|
11475
11487
|
name: "RSASSA-PKCS1-v1_5",
|
|
11476
11488
|
modulusLength: 2048,
|
|
@@ -11485,7 +11497,7 @@ var CryptoController = class {
|
|
|
11485
11497
|
this._fingerprint = await computeJwkThumbprint(this._publicJwk);
|
|
11486
11498
|
this._initialized = true;
|
|
11487
11499
|
await saveKeyPairToDB(this._keyPair);
|
|
11488
|
-
logger$
|
|
11500
|
+
logger$28.debug("[DPoP] Key pair generated and persisted, fingerprint:", this._fingerprint);
|
|
11489
11501
|
return this._fingerprint;
|
|
11490
11502
|
}
|
|
11491
11503
|
/**
|
|
@@ -11551,7 +11563,7 @@ var CryptoController = class {
|
|
|
11551
11563
|
this._fingerprint = null;
|
|
11552
11564
|
this._initialized = false;
|
|
11553
11565
|
deleteKeyPairFromDB();
|
|
11554
|
-
logger$
|
|
11566
|
+
logger$28.debug("[DPoP] Controller destroyed");
|
|
11555
11567
|
}
|
|
11556
11568
|
get publicJwk() {
|
|
11557
11569
|
if (!this._publicJwk) throw new DPoPInitError("CryptoController not initialized. Call init() first.");
|
|
@@ -11574,8 +11586,8 @@ var CryptoController = class {
|
|
|
11574
11586
|
|
|
11575
11587
|
//#endregion
|
|
11576
11588
|
//#region src/controllers/NetworkMonitor.ts
|
|
11577
|
-
var import_cjs$
|
|
11578
|
-
const logger$
|
|
11589
|
+
var import_cjs$28 = require_cjs();
|
|
11590
|
+
const logger$27 = getLogger();
|
|
11579
11591
|
/**
|
|
11580
11592
|
* Safely check whether we are running in a browser environment
|
|
11581
11593
|
* with `window` and the relevant event targets.
|
|
@@ -11618,13 +11630,13 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11618
11630
|
this.attachListeners();
|
|
11619
11631
|
}
|
|
11620
11632
|
get isOnline$() {
|
|
11621
|
-
return this._isOnline$.asObservable().pipe((0, import_cjs$
|
|
11633
|
+
return this._isOnline$.asObservable().pipe((0, import_cjs$28.takeUntil)(this._destroyed$));
|
|
11622
11634
|
}
|
|
11623
11635
|
get isOnline() {
|
|
11624
11636
|
return this._isOnline$.value;
|
|
11625
11637
|
}
|
|
11626
11638
|
get networkChange$() {
|
|
11627
|
-
return this._networkChange$.asObservable().pipe((0, import_cjs$
|
|
11639
|
+
return this._networkChange$.asObservable().pipe((0, import_cjs$28.takeUntil)(this._destroyed$));
|
|
11628
11640
|
}
|
|
11629
11641
|
destroy() {
|
|
11630
11642
|
this.removeListeners();
|
|
@@ -11632,7 +11644,7 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11632
11644
|
}
|
|
11633
11645
|
attachListeners() {
|
|
11634
11646
|
if (!hasBrowserNetworkEvents()) {
|
|
11635
|
-
logger$
|
|
11647
|
+
logger$27.debug("NetworkMonitor: no browser environment detected, skipping event listeners");
|
|
11636
11648
|
return;
|
|
11637
11649
|
}
|
|
11638
11650
|
window.addEventListener("online", this._onOnline);
|
|
@@ -11640,7 +11652,7 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11640
11652
|
const connection = getNetworkConnection();
|
|
11641
11653
|
if (connection) connection.addEventListener("change", this._onConnectionChange);
|
|
11642
11654
|
this._listenersAttached = true;
|
|
11643
|
-
logger$
|
|
11655
|
+
logger$27.debug("NetworkMonitor: event listeners attached");
|
|
11644
11656
|
}
|
|
11645
11657
|
removeListeners() {
|
|
11646
11658
|
if (!this._listenersAttached) return;
|
|
@@ -11651,10 +11663,10 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11651
11663
|
if (connection) connection.removeEventListener("change", this._onConnectionChange);
|
|
11652
11664
|
}
|
|
11653
11665
|
this._listenersAttached = false;
|
|
11654
|
-
logger$
|
|
11666
|
+
logger$27.debug("NetworkMonitor: event listeners removed");
|
|
11655
11667
|
}
|
|
11656
11668
|
handleOnline() {
|
|
11657
|
-
logger$
|
|
11669
|
+
logger$27.info("NetworkMonitor: browser went online");
|
|
11658
11670
|
this._isOnline$.next(true);
|
|
11659
11671
|
this._networkChange$.next({
|
|
11660
11672
|
type: "online",
|
|
@@ -11663,7 +11675,7 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11663
11675
|
});
|
|
11664
11676
|
}
|
|
11665
11677
|
handleOffline() {
|
|
11666
|
-
logger$
|
|
11678
|
+
logger$27.info("NetworkMonitor: browser went offline");
|
|
11667
11679
|
this._isOnline$.next(false);
|
|
11668
11680
|
this._networkChange$.next({
|
|
11669
11681
|
type: "offline",
|
|
@@ -11672,7 +11684,7 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11672
11684
|
}
|
|
11673
11685
|
handleConnectionChange() {
|
|
11674
11686
|
const networkType = getNetworkType();
|
|
11675
|
-
logger$
|
|
11687
|
+
logger$27.info(`NetworkMonitor: connection changed — effectiveType=${networkType ?? "unknown"}`);
|
|
11676
11688
|
this._networkChange$.next({
|
|
11677
11689
|
type: "connection_change",
|
|
11678
11690
|
timestamp: Date.now(),
|
|
@@ -11787,8 +11799,8 @@ function getNavigatorMediaDevices() {
|
|
|
11787
11799
|
|
|
11788
11800
|
//#endregion
|
|
11789
11801
|
//#region src/controllers/PreflightRunner.ts
|
|
11790
|
-
var import_cjs$
|
|
11791
|
-
const logger$
|
|
11802
|
+
var import_cjs$27 = require_cjs();
|
|
11803
|
+
const logger$26 = getLogger();
|
|
11792
11804
|
const DEFAULT_MEDIA_TEST_DURATION_S = 10;
|
|
11793
11805
|
const ICE_GATHERING_TIMEOUT_MS = 1e4;
|
|
11794
11806
|
const SIGNALING_RTT_TIMEOUT_MS = 5e3;
|
|
@@ -11837,7 +11849,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11837
11849
|
if (!this._options.skipMediaTest) try {
|
|
11838
11850
|
bandwidth = await this.testMediaBandwidth(destination);
|
|
11839
11851
|
} catch (error) {
|
|
11840
|
-
logger$
|
|
11852
|
+
logger$26.warn("[PreflightRunner] Media bandwidth test failed:", error);
|
|
11841
11853
|
warnings.push("Media bandwidth test failed");
|
|
11842
11854
|
}
|
|
11843
11855
|
return {
|
|
@@ -11849,7 +11861,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11849
11861
|
warnings
|
|
11850
11862
|
};
|
|
11851
11863
|
} catch (error) {
|
|
11852
|
-
logger$
|
|
11864
|
+
logger$26.error("[PreflightRunner] Preflight test failed:", error);
|
|
11853
11865
|
throw new PreflightError("preflight", error instanceof Error ? error : new Error(String(error)));
|
|
11854
11866
|
} finally {
|
|
11855
11867
|
this.destroy();
|
|
@@ -11880,7 +11892,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11880
11892
|
if (track.kind === "video" && track.readyState === "live") videoWorking = true;
|
|
11881
11893
|
}
|
|
11882
11894
|
} catch (error) {
|
|
11883
|
-
logger$
|
|
11895
|
+
logger$26.warn("[PreflightRunner] Device test failed:", error);
|
|
11884
11896
|
} finally {
|
|
11885
11897
|
if (audioStream) audioStream.getTracks().forEach((t) => t.stop());
|
|
11886
11898
|
}
|
|
@@ -11907,7 +11919,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11907
11919
|
const candidateTypes = /* @__PURE__ */ new Set();
|
|
11908
11920
|
const startTime = Date.now();
|
|
11909
11921
|
const gatheringComplete = new Promise((resolve) => {
|
|
11910
|
-
const timer$
|
|
11922
|
+
const timer$4 = setTimeout(resolve, ICE_GATHERING_TIMEOUT_MS);
|
|
11911
11923
|
peerConnection.onicecandidate = (event) => {
|
|
11912
11924
|
if (event.candidate) {
|
|
11913
11925
|
const candidateStr = event.candidate.candidate;
|
|
@@ -11915,7 +11927,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11915
11927
|
if (candidateStr.includes("typ srflx")) candidateTypes.add("srflx");
|
|
11916
11928
|
if (candidateStr.includes("typ relay")) candidateTypes.add("relay");
|
|
11917
11929
|
} else {
|
|
11918
|
-
clearTimeout(timer$
|
|
11930
|
+
clearTimeout(timer$4);
|
|
11919
11931
|
resolve();
|
|
11920
11932
|
}
|
|
11921
11933
|
};
|
|
@@ -11938,7 +11950,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11938
11950
|
rttMs
|
|
11939
11951
|
};
|
|
11940
11952
|
} catch (error) {
|
|
11941
|
-
logger$
|
|
11953
|
+
logger$26.warn("[PreflightRunner] ICE connectivity test failed:", error);
|
|
11942
11954
|
return {
|
|
11943
11955
|
type: "failed",
|
|
11944
11956
|
turnReachable: false,
|
|
@@ -11956,7 +11968,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11956
11968
|
audio: true,
|
|
11957
11969
|
video: false
|
|
11958
11970
|
});
|
|
11959
|
-
await (0, import_cjs$
|
|
11971
|
+
await (0, import_cjs$27.firstValueFrom)(call.status$.pipe((0, import_cjs$27.filter)((s) => s === "connected"), (0, import_cjs$27.take)(1), (0, import_cjs$27.timeout)(SIGNALING_RTT_TIMEOUT_MS)));
|
|
11960
11972
|
const durationMs = this._options.duration * 1e3;
|
|
11961
11973
|
await new Promise((resolve) => setTimeout(resolve, durationMs));
|
|
11962
11974
|
const metrics = call.networkMetrics;
|
|
@@ -11985,8 +11997,8 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11985
11997
|
|
|
11986
11998
|
//#endregion
|
|
11987
11999
|
//#region src/controllers/VisibilityController.ts
|
|
11988
|
-
var import_cjs$
|
|
11989
|
-
const logger$
|
|
12000
|
+
var import_cjs$26 = require_cjs();
|
|
12001
|
+
const logger$25 = getLogger();
|
|
11990
12002
|
/**
|
|
11991
12003
|
* Checks whether the document visibility API is available.
|
|
11992
12004
|
*/
|
|
@@ -12023,15 +12035,15 @@ var VisibilityController = class extends Destroyable {
|
|
|
12023
12035
|
this._boundHandler = this._handleVisibilityChange.bind(this);
|
|
12024
12036
|
if (this._hasVisibilityApi) {
|
|
12025
12037
|
document.addEventListener("visibilitychange", this._boundHandler);
|
|
12026
|
-
logger$
|
|
12027
|
-
} else logger$
|
|
12038
|
+
logger$25.debug("VisibilityController: listening for visibilitychange events");
|
|
12039
|
+
} else logger$25.debug("VisibilityController: document visibility API not available, defaulting to visible");
|
|
12028
12040
|
}
|
|
12029
12041
|
/**
|
|
12030
12042
|
* Observable of the current visibility state.
|
|
12031
12043
|
* Emits 'visible' or 'hidden'. Always starts with the current state.
|
|
12032
12044
|
*/
|
|
12033
12045
|
get visibility$() {
|
|
12034
|
-
return this._visibility$.pipe((0, import_cjs$
|
|
12046
|
+
return this._visibility$.pipe((0, import_cjs$26.takeUntil)(this._destroyed$));
|
|
12035
12047
|
}
|
|
12036
12048
|
/**
|
|
12037
12049
|
* The current visibility state value.
|
|
@@ -12044,12 +12056,12 @@ var VisibilityController = class extends Destroyable {
|
|
|
12044
12056
|
* Each event includes the previous state, new state, and timestamp.
|
|
12045
12057
|
*/
|
|
12046
12058
|
get visibilityChange$() {
|
|
12047
|
-
return this._visibilityChange$.pipe((0, import_cjs$
|
|
12059
|
+
return this._visibilityChange$.pipe((0, import_cjs$26.takeUntil)(this._destroyed$));
|
|
12048
12060
|
}
|
|
12049
12061
|
destroy() {
|
|
12050
12062
|
if (this._hasVisibilityApi) {
|
|
12051
12063
|
document.removeEventListener("visibilitychange", this._boundHandler);
|
|
12052
|
-
logger$
|
|
12064
|
+
logger$25.debug("VisibilityController: removed visibilitychange listener");
|
|
12053
12065
|
}
|
|
12054
12066
|
super.destroy();
|
|
12055
12067
|
}
|
|
@@ -12067,7 +12079,7 @@ var VisibilityController = class extends Destroyable {
|
|
|
12067
12079
|
timestamp: Date.now()
|
|
12068
12080
|
};
|
|
12069
12081
|
this._visibilityChange$.next(changeEvent);
|
|
12070
|
-
logger$
|
|
12082
|
+
logger$25.debug("VisibilityController: visibility changed", {
|
|
12071
12083
|
from: previousState,
|
|
12072
12084
|
to: newState
|
|
12073
12085
|
});
|
|
@@ -12076,13 +12088,13 @@ var VisibilityController = class extends Destroyable {
|
|
|
12076
12088
|
|
|
12077
12089
|
//#endregion
|
|
12078
12090
|
//#region src/behaviors/Fetchable.ts
|
|
12079
|
-
var import_cjs$
|
|
12091
|
+
var import_cjs$25 = require_cjs();
|
|
12080
12092
|
var Fetchable = class extends Destroyable {
|
|
12081
12093
|
constructor(fromPath, http) {
|
|
12082
12094
|
super();
|
|
12083
12095
|
this.fromPath = fromPath;
|
|
12084
12096
|
this.http = http;
|
|
12085
|
-
this.fetched$ = (0, import_cjs$
|
|
12097
|
+
this.fetched$ = (0, import_cjs$25.defer)(() => (0, import_cjs$25.from)(this.fetch())).pipe((0, import_cjs$25.shareReplay)(1), (0, import_cjs$25.takeUntil)(this.destroyed$));
|
|
12086
12098
|
}
|
|
12087
12099
|
async fetch() {
|
|
12088
12100
|
const response = await this.http.request({
|
|
@@ -12100,14 +12112,14 @@ var Fetchable = class extends Destroyable {
|
|
|
12100
12112
|
};
|
|
12101
12113
|
|
|
12102
12114
|
//#endregion
|
|
12103
|
-
//#region src/core/entities/
|
|
12115
|
+
//#region src/core/entities/User.ts
|
|
12104
12116
|
/**
|
|
12105
|
-
* Authenticated
|
|
12117
|
+
* Authenticated user profile.
|
|
12106
12118
|
*
|
|
12107
12119
|
* Fetched automatically when a {@link SignalWire} connects.
|
|
12108
12120
|
* Contains identity, contact, and organization details.
|
|
12109
12121
|
*/
|
|
12110
|
-
var
|
|
12122
|
+
var User = class extends Fetchable {
|
|
12111
12123
|
constructor(http) {
|
|
12112
12124
|
super("/api/fabric/subscriber/info", http);
|
|
12113
12125
|
}
|
|
@@ -12317,20 +12329,18 @@ const RPCEventAckResponse = (id) => makeRPCResponse({
|
|
|
12317
12329
|
|
|
12318
12330
|
//#endregion
|
|
12319
12331
|
//#region src/managers/AttachManager.ts
|
|
12320
|
-
const logger$
|
|
12332
|
+
const logger$24 = getLogger();
|
|
12321
12333
|
var AttachManager = class {
|
|
12322
12334
|
constructor(storage, deviceController, reconnectCallsTimeout, attachKey) {
|
|
12323
12335
|
this.storage = storage;
|
|
12324
12336
|
this.deviceController = deviceController;
|
|
12325
12337
|
this.reconnectCallsTimeout = reconnectCallsTimeout;
|
|
12326
12338
|
this.attachKey = attachKey;
|
|
12339
|
+
this.writeQueue = Promise.resolve();
|
|
12327
12340
|
}
|
|
12328
12341
|
async detachAll() {
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
id: callId,
|
|
12332
|
-
nodeId: attached[callId].nodeId,
|
|
12333
|
-
mediaDirections: attached[callId].mediaDirections
|
|
12342
|
+
await this.mutate((attached) => {
|
|
12343
|
+
return {};
|
|
12334
12344
|
});
|
|
12335
12345
|
}
|
|
12336
12346
|
setSession(session) {
|
|
@@ -12340,7 +12350,7 @@ var AttachManager = class {
|
|
|
12340
12350
|
try {
|
|
12341
12351
|
return await this.storage.getItem(this.attachKey) ?? {};
|
|
12342
12352
|
} catch (error) {
|
|
12343
|
-
logger$
|
|
12353
|
+
logger$24.warn("[AttachManager] Failed to retrieve attached calls from storage", error);
|
|
12344
12354
|
return {};
|
|
12345
12355
|
}
|
|
12346
12356
|
}
|
|
@@ -12348,34 +12358,50 @@ var AttachManager = class {
|
|
|
12348
12358
|
try {
|
|
12349
12359
|
await this.storage.setItem(this.attachKey, attached);
|
|
12350
12360
|
} catch (error) {
|
|
12351
|
-
logger$
|
|
12361
|
+
logger$24.warn("[AttachManager] Failed to write attached calls to storage", error);
|
|
12352
12362
|
}
|
|
12353
12363
|
}
|
|
12364
|
+
/**
|
|
12365
|
+
* Serialize a read-modify-write operation against the attached-calls
|
|
12366
|
+
* storage. The mutator receives the current state and returns the new
|
|
12367
|
+
* state. Concurrent calls queue behind the in-flight one so writes never
|
|
12368
|
+
* interleave.
|
|
12369
|
+
*/
|
|
12370
|
+
async mutate(mutator) {
|
|
12371
|
+
const next = this.writeQueue.then(async () => {
|
|
12372
|
+
const updated = await mutator(await this.readAttached());
|
|
12373
|
+
await this.writeAttached(updated);
|
|
12374
|
+
});
|
|
12375
|
+
this.writeQueue = next.catch(() => void 0);
|
|
12376
|
+
return next;
|
|
12377
|
+
}
|
|
12354
12378
|
async attach(call) {
|
|
12355
12379
|
if (!call.to) {
|
|
12356
|
-
logger$
|
|
12380
|
+
logger$24.warn("[AttachManager] Skip attach for calls with no destination");
|
|
12357
12381
|
return;
|
|
12358
12382
|
}
|
|
12383
|
+
const destination = call.to;
|
|
12359
12384
|
const attachment = {
|
|
12360
12385
|
nodeId: call.nodeId,
|
|
12361
|
-
destination
|
|
12386
|
+
destination,
|
|
12362
12387
|
mediaDirections: call.mediaDirections,
|
|
12363
12388
|
audioInputDevice: call.mediaDirections.audio !== "inactive" ? this.deviceController.selectedAudioInputDevice : null,
|
|
12364
12389
|
videoInputDevice: call.mediaDirections.video !== "inactive" ? this.deviceController.selectedVideoInputDevice : null,
|
|
12365
12390
|
attachedAt: Date.now()
|
|
12366
12391
|
};
|
|
12367
|
-
|
|
12368
|
-
...
|
|
12392
|
+
await this.mutate((attached) => ({
|
|
12393
|
+
...attached,
|
|
12369
12394
|
[call.id]: attachment
|
|
12370
|
-
};
|
|
12371
|
-
await this.writeAttached(updated);
|
|
12395
|
+
}));
|
|
12372
12396
|
}
|
|
12373
12397
|
async detach(call) {
|
|
12374
|
-
|
|
12375
|
-
|
|
12398
|
+
await this.mutate((attached) => {
|
|
12399
|
+
const { [call.id]: _, ...remaining } = attached;
|
|
12400
|
+
return remaining;
|
|
12401
|
+
});
|
|
12376
12402
|
}
|
|
12377
12403
|
async flush() {
|
|
12378
|
-
await this.
|
|
12404
|
+
await this.mutate(() => ({}));
|
|
12379
12405
|
}
|
|
12380
12406
|
/**
|
|
12381
12407
|
* Reattach to previously active calls by sending verto.invite with
|
|
@@ -12404,15 +12430,15 @@ var AttachManager = class {
|
|
|
12404
12430
|
callId,
|
|
12405
12431
|
...options
|
|
12406
12432
|
});
|
|
12407
|
-
logger$
|
|
12433
|
+
logger$24.info(`[AttachManager] Reattached call ${callId} (attempt ${attempt})`);
|
|
12408
12434
|
succeeded = true;
|
|
12409
12435
|
break;
|
|
12410
12436
|
} catch (error) {
|
|
12411
|
-
logger$
|
|
12437
|
+
logger$24.warn(`[AttachManager] Reattach attempt ${attempt}/3 failed for call ${callId}:`, error);
|
|
12412
12438
|
if (attempt < 3) await new Promise((r) => setTimeout(r, (attempt + 1) * 1e3));
|
|
12413
12439
|
}
|
|
12414
12440
|
if (!succeeded) {
|
|
12415
|
-
logger$
|
|
12441
|
+
logger$24.warn(`[AttachManager] Reattach failed after 3 attempts for call ${callId}, removing reference`);
|
|
12416
12442
|
await this.detach({
|
|
12417
12443
|
id: callId,
|
|
12418
12444
|
mediaDirections: attachment.mediaDirections
|
|
@@ -12447,20 +12473,31 @@ var AttachManager = class {
|
|
|
12447
12473
|
};
|
|
12448
12474
|
}
|
|
12449
12475
|
/**
|
|
12450
|
-
*
|
|
12451
|
-
*
|
|
12476
|
+
* Look up stored attachment data for a call id and return CallOptions
|
|
12477
|
+
* suitable for rehydrating a reattached call. Returns undefined when no
|
|
12478
|
+
* matching entry exists in storage.
|
|
12479
|
+
*
|
|
12480
|
+
* Used by the session-level verto.attach handler when the server pushes
|
|
12481
|
+
* an attach event for a call the client doesn't have an object for yet
|
|
12482
|
+
* (e.g. after a reload).
|
|
12452
12483
|
*/
|
|
12453
|
-
consumePendingAttachment(
|
|
12454
|
-
async detachExpired() {
|
|
12484
|
+
async consumePendingAttachment(callId) {
|
|
12455
12485
|
const attached = await this.readAttached();
|
|
12486
|
+
if (!Object.hasOwn(attached, callId)) return;
|
|
12487
|
+
return this.buildCallOptions(attached[callId]);
|
|
12488
|
+
}
|
|
12489
|
+
async detachExpired() {
|
|
12456
12490
|
const now = Date.now();
|
|
12457
12491
|
const timeout$5 = this.reconnectCallsTimeout;
|
|
12458
|
-
|
|
12459
|
-
if (expired.length > 0) {
|
|
12492
|
+
await this.mutate((attached) => {
|
|
12460
12493
|
const remaining = { ...attached };
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12494
|
+
let changed = false;
|
|
12495
|
+
for (const [callId, attachment] of Object.entries(attached)) if (now - attachment.attachedAt > timeout$5) {
|
|
12496
|
+
delete remaining[callId];
|
|
12497
|
+
changed = true;
|
|
12498
|
+
}
|
|
12499
|
+
return changed ? remaining : attached;
|
|
12500
|
+
});
|
|
12464
12501
|
}
|
|
12465
12502
|
};
|
|
12466
12503
|
|
|
@@ -12507,12 +12544,12 @@ var require_race = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
12507
12544
|
exports.race = void 0;
|
|
12508
12545
|
var argsOrArgArray_1 = require_argsOrArgArray();
|
|
12509
12546
|
var raceWith_1$1 = require_raceWith();
|
|
12510
|
-
function race$
|
|
12547
|
+
function race$4() {
|
|
12511
12548
|
var args = [];
|
|
12512
12549
|
for (var _i = 0; _i < arguments.length; _i++) args[_i] = arguments[_i];
|
|
12513
12550
|
return raceWith_1$1.raceWith.apply(void 0, __spreadArray([], __read(argsOrArgArray_1.argsOrArgArray(args))));
|
|
12514
12551
|
}
|
|
12515
|
-
exports.race = race$
|
|
12552
|
+
exports.race = race$4;
|
|
12516
12553
|
}));
|
|
12517
12554
|
|
|
12518
12555
|
//#endregion
|
|
@@ -13440,7 +13477,7 @@ function computeCapabilities(capabilities) {
|
|
|
13440
13477
|
|
|
13441
13478
|
//#endregion
|
|
13442
13479
|
//#region src/core/capabilities/SelfCapabilities.ts
|
|
13443
|
-
var import_cjs$
|
|
13480
|
+
var import_cjs$24 = require_cjs();
|
|
13444
13481
|
/**
|
|
13445
13482
|
* SelfCapabilities manages the capability state for the self participant.
|
|
13446
13483
|
*
|
|
@@ -13476,7 +13513,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13476
13513
|
}
|
|
13477
13514
|
/** Observable for self member capabilities */
|
|
13478
13515
|
get self$() {
|
|
13479
|
-
return this.cachedObservable("self$", () => this._state$.pipe((0, import_cjs$
|
|
13516
|
+
return this.cachedObservable("self$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.self), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13480
13517
|
}
|
|
13481
13518
|
/** Current self member capabilities */
|
|
13482
13519
|
get self() {
|
|
@@ -13484,7 +13521,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13484
13521
|
}
|
|
13485
13522
|
/** Observable for other member capabilities */
|
|
13486
13523
|
get member$() {
|
|
13487
|
-
return this.cachedObservable("member$", () => this._state$.pipe((0, import_cjs$
|
|
13524
|
+
return this.cachedObservable("member$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.member), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13488
13525
|
}
|
|
13489
13526
|
/** Current other member capabilities */
|
|
13490
13527
|
get member() {
|
|
@@ -13492,7 +13529,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13492
13529
|
}
|
|
13493
13530
|
/** Observable for end call capability */
|
|
13494
13531
|
get end$() {
|
|
13495
|
-
return this.cachedObservable("end$", () => this._state$.pipe((0, import_cjs$
|
|
13532
|
+
return this.cachedObservable("end$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.end), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13496
13533
|
}
|
|
13497
13534
|
/** Current end call capability */
|
|
13498
13535
|
get end() {
|
|
@@ -13500,7 +13537,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13500
13537
|
}
|
|
13501
13538
|
/** Observable for set layout capability */
|
|
13502
13539
|
get setLayout$() {
|
|
13503
|
-
return this.cachedObservable("setLayout$", () => this._state$.pipe((0, import_cjs$
|
|
13540
|
+
return this.cachedObservable("setLayout$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.setLayout), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13504
13541
|
}
|
|
13505
13542
|
/** Current set layout capability */
|
|
13506
13543
|
get setLayout() {
|
|
@@ -13508,7 +13545,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13508
13545
|
}
|
|
13509
13546
|
/** Observable for send digit capability */
|
|
13510
13547
|
get sendDigit$() {
|
|
13511
|
-
return this.cachedObservable("sendDigit$", () => this._state$.pipe((0, import_cjs$
|
|
13548
|
+
return this.cachedObservable("sendDigit$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.sendDigit), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13512
13549
|
}
|
|
13513
13550
|
/** Current send digit capability */
|
|
13514
13551
|
get sendDigit() {
|
|
@@ -13516,7 +13553,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13516
13553
|
}
|
|
13517
13554
|
/** Observable for vmuted hide capability */
|
|
13518
13555
|
get vmutedHide$() {
|
|
13519
|
-
return this.cachedObservable("vmutedHide$", () => this._state$.pipe((0, import_cjs$
|
|
13556
|
+
return this.cachedObservable("vmutedHide$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.vmutedHide), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13520
13557
|
}
|
|
13521
13558
|
/** Current vmuted hide capability */
|
|
13522
13559
|
get vmutedHide() {
|
|
@@ -13524,7 +13561,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13524
13561
|
}
|
|
13525
13562
|
/** Observable for lock capability */
|
|
13526
13563
|
get lock$() {
|
|
13527
|
-
return this.cachedObservable("lock$", () => this._state$.pipe((0, import_cjs$
|
|
13564
|
+
return this.cachedObservable("lock$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.lock), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13528
13565
|
}
|
|
13529
13566
|
/** Current lock capability */
|
|
13530
13567
|
get lock() {
|
|
@@ -13532,7 +13569,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13532
13569
|
}
|
|
13533
13570
|
/** Observable for device capability */
|
|
13534
13571
|
get device$() {
|
|
13535
|
-
return this.cachedObservable("device$", () => this._state$.pipe((0, import_cjs$
|
|
13572
|
+
return this.cachedObservable("device$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.device), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13536
13573
|
}
|
|
13537
13574
|
/** Current device capability */
|
|
13538
13575
|
get device() {
|
|
@@ -13540,7 +13577,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13540
13577
|
}
|
|
13541
13578
|
/** Observable for screenshare capability */
|
|
13542
13579
|
get screenshare$() {
|
|
13543
|
-
return this.cachedObservable("screenshare$", () => this._state$.pipe((0, import_cjs$
|
|
13580
|
+
return this.cachedObservable("screenshare$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.screenshare), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13544
13581
|
}
|
|
13545
13582
|
/** Current screenshare capability */
|
|
13546
13583
|
get screenshare() {
|
|
@@ -13568,7 +13605,7 @@ function toggleHandraiseMethod(is) {
|
|
|
13568
13605
|
|
|
13569
13606
|
//#endregion
|
|
13570
13607
|
//#region src/core/entities/Participant.ts
|
|
13571
|
-
const logger$
|
|
13608
|
+
const logger$23 = getLogger();
|
|
13572
13609
|
const initialState = {};
|
|
13573
13610
|
/**
|
|
13574
13611
|
* Represents a participant in a call.
|
|
@@ -13620,15 +13657,35 @@ var Participant = class extends Destroyable {
|
|
|
13620
13657
|
get deaf$() {
|
|
13621
13658
|
return this.cachedObservable("deaf$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.deaf), (0, import_operators$1.distinctUntilChanged)()));
|
|
13622
13659
|
}
|
|
13623
|
-
/**
|
|
13660
|
+
/**
|
|
13661
|
+
* Observable of the participant's **server-side** microphone input volume
|
|
13662
|
+
* as reported by the mix engine. This is gain applied on the bridged audio
|
|
13663
|
+
* leg (FreeSWITCH channel read volume), NOT the local browser mic. For a
|
|
13664
|
+
* local PC mic control, see {@link Call.setLocalMicrophoneGain}.
|
|
13665
|
+
*
|
|
13666
|
+
* @see {@link setAudioInputVolume}
|
|
13667
|
+
*/
|
|
13624
13668
|
get inputVolume$() {
|
|
13625
13669
|
return this.cachedObservable("inputVolume$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.input_volume), (0, import_operators$1.distinctUntilChanged)()));
|
|
13626
13670
|
}
|
|
13627
|
-
/**
|
|
13671
|
+
/**
|
|
13672
|
+
* Observable of the participant's **server-side** speaker output volume as
|
|
13673
|
+
* reported by the mix engine (FreeSWITCH channel write volume). NOT the
|
|
13674
|
+
* local HTML `<audio>` element volume — set that on your own element.
|
|
13675
|
+
*
|
|
13676
|
+
* @see {@link setAudioOutputVolume}
|
|
13677
|
+
*/
|
|
13628
13678
|
get outputVolume$() {
|
|
13629
13679
|
return this.cachedObservable("outputVolume$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.output_volume), (0, import_operators$1.distinctUntilChanged)()));
|
|
13630
13680
|
}
|
|
13631
|
-
/**
|
|
13681
|
+
/**
|
|
13682
|
+
* Observable of the **conference-only** microphone energy/gate sensitivity
|
|
13683
|
+
* level for this member. Routes through the conferencing mix engine and has
|
|
13684
|
+
* no effect on 1:1 WebRTC calls. Populated from `member.updated` events for
|
|
13685
|
+
* conference members.
|
|
13686
|
+
*
|
|
13687
|
+
* @see {@link setAudioInputSensitivity}
|
|
13688
|
+
*/
|
|
13632
13689
|
get inputSensitivity$() {
|
|
13633
13690
|
return this.cachedObservable("inputSensitivity$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.input_sensitivity), (0, import_operators$1.distinctUntilChanged)()));
|
|
13634
13691
|
}
|
|
@@ -13656,9 +13713,9 @@ var Participant = class extends Destroyable {
|
|
|
13656
13713
|
get meta$() {
|
|
13657
13714
|
return this.cachedObservable("meta$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.meta), (0, import_operators$1.distinctUntilChanged)()));
|
|
13658
13715
|
}
|
|
13659
|
-
/** Observable of the participant's
|
|
13660
|
-
get
|
|
13661
|
-
return this.cachedObservable("
|
|
13716
|
+
/** Observable of the participant's user ID. */
|
|
13717
|
+
get userId$() {
|
|
13718
|
+
return this.cachedObservable("userId$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.subscriber_id), (0, import_operators$1.distinctUntilChanged)()));
|
|
13662
13719
|
}
|
|
13663
13720
|
/** Observable of the participant's address ID. */
|
|
13664
13721
|
get addressId$() {
|
|
@@ -13716,15 +13773,25 @@ var Participant = class extends Destroyable {
|
|
|
13716
13773
|
get deaf() {
|
|
13717
13774
|
return this._state$.value.deaf ?? false;
|
|
13718
13775
|
}
|
|
13719
|
-
/**
|
|
13776
|
+
/**
|
|
13777
|
+
* Current **server-side** microphone input volume as reported by the mix
|
|
13778
|
+
* engine, or `undefined` if not set. Not the local PC mic — see
|
|
13779
|
+
* {@link Call.setLocalMicrophoneGain} for browser-side control.
|
|
13780
|
+
*/
|
|
13720
13781
|
get inputVolume() {
|
|
13721
13782
|
return this._state$.value.input_volume;
|
|
13722
13783
|
}
|
|
13723
|
-
/**
|
|
13784
|
+
/**
|
|
13785
|
+
* Current **server-side** speaker output volume from the mix engine, or
|
|
13786
|
+
* `undefined` if not set. Not the local `<audio>` element volume.
|
|
13787
|
+
*/
|
|
13724
13788
|
get outputVolume() {
|
|
13725
13789
|
return this._state$.value.output_volume;
|
|
13726
13790
|
}
|
|
13727
|
-
/**
|
|
13791
|
+
/**
|
|
13792
|
+
* Current **conference-only** microphone sensitivity/gate level, or
|
|
13793
|
+
* `undefined` if not set. Applies only to conference members.
|
|
13794
|
+
*/
|
|
13728
13795
|
get inputSensitivity() {
|
|
13729
13796
|
return this._state$.value.input_sensitivity;
|
|
13730
13797
|
}
|
|
@@ -13752,8 +13819,8 @@ var Participant = class extends Destroyable {
|
|
|
13752
13819
|
get meta() {
|
|
13753
13820
|
return this._state$.value.meta;
|
|
13754
13821
|
}
|
|
13755
|
-
/**
|
|
13756
|
-
get
|
|
13822
|
+
/** User ID of this participant, or `undefined` if not available. */
|
|
13823
|
+
get userId() {
|
|
13757
13824
|
return this._state$.value.subscriber_id;
|
|
13758
13825
|
}
|
|
13759
13826
|
/** Address ID of this participant, or `undefined` if not available. */
|
|
@@ -13828,19 +13895,44 @@ var Participant = class extends Destroyable {
|
|
|
13828
13895
|
async toggleLowbitrate() {
|
|
13829
13896
|
throw new UnimplementedError();
|
|
13830
13897
|
}
|
|
13831
|
-
/**
|
|
13898
|
+
/**
|
|
13899
|
+
* Adjusts the **conference-only** microphone energy gate / sensitivity level
|
|
13900
|
+
* for this member. Routes through the conferencing mix engine
|
|
13901
|
+
* (`signalwire.conferencing member.set_input_sensitivity`) and has no effect
|
|
13902
|
+
* on 1:1 WebRTC calls — for those, use browser audio constraints via
|
|
13903
|
+
* {@link Call.setNoiseSuppression} / {@link Call.setAutoGainControl}.
|
|
13904
|
+
*
|
|
13905
|
+
* This is **not** a local PC mic gain control; it only changes how the
|
|
13906
|
+
* server-side mixer decides to open the mic gate on this participant.
|
|
13907
|
+
*
|
|
13908
|
+
* @param value - Sensitivity level as understood by the conference engine
|
|
13909
|
+
* (integer, larger values are more sensitive).
|
|
13910
|
+
*/
|
|
13832
13911
|
async setAudioInputSensitivity(value) {
|
|
13833
13912
|
await this.executeMethod(this.id, "call.microphone.sensitivity.set", { sensitivity: value });
|
|
13834
13913
|
}
|
|
13835
13914
|
/**
|
|
13836
|
-
* Sets the microphone
|
|
13915
|
+
* Sets the **server-side** microphone volume on this participant's bridged
|
|
13916
|
+
* call leg. Applies a multiplier to the audio flowing through the mix
|
|
13917
|
+
* engine (FreeSWITCH channel read volume) — changes what other participants
|
|
13918
|
+
* hear, not what the local browser captures.
|
|
13919
|
+
*
|
|
13920
|
+
* For local PC mic gain, use {@link Call.setLocalMicrophoneGain} instead.
|
|
13921
|
+
*
|
|
13837
13922
|
* @param value - Volume level (0-100).
|
|
13838
13923
|
*/
|
|
13839
13924
|
async setAudioInputVolume(value) {
|
|
13840
13925
|
await this.executeMethod(this.id, "call.microphone.volume.set", { volume: value });
|
|
13841
13926
|
}
|
|
13842
13927
|
/**
|
|
13843
|
-
* Sets the speaker
|
|
13928
|
+
* Sets the **server-side** speaker volume on this participant's bridged call
|
|
13929
|
+
* leg (FreeSWITCH channel write volume) — what this participant hears from
|
|
13930
|
+
* the mix before it reaches their client.
|
|
13931
|
+
*
|
|
13932
|
+
* For local playback volume (the `<audio>` element the consumer attaches
|
|
13933
|
+
* `remoteStream` to), set `audioElement.volume` directly in the consumer's
|
|
13934
|
+
* code.
|
|
13935
|
+
*
|
|
13844
13936
|
* @param value - Volume level (0-100).
|
|
13845
13937
|
*/
|
|
13846
13938
|
async setAudioOutputVolume(value) {
|
|
@@ -13946,7 +14038,7 @@ var SelfParticipant = class extends Participant {
|
|
|
13946
14038
|
try {
|
|
13947
14039
|
await this.vertoManager.addScreenMedia();
|
|
13948
14040
|
} catch (error) {
|
|
13949
|
-
logger$
|
|
14041
|
+
logger$23.error("[Participant.startScreenShare] Screen share error:", error);
|
|
13950
14042
|
}
|
|
13951
14043
|
}
|
|
13952
14044
|
/** Observable of the current screen share status. */
|
|
@@ -13966,7 +14058,7 @@ var SelfParticipant = class extends Participant {
|
|
|
13966
14058
|
try {
|
|
13967
14059
|
await this.vertoManager.addInputDevice(options);
|
|
13968
14060
|
} catch (error) {
|
|
13969
|
-
logger$
|
|
14061
|
+
logger$23.error("[Participant.startScreenShare] Screen share error:", error);
|
|
13970
14062
|
}
|
|
13971
14063
|
}
|
|
13972
14064
|
/** Removes an additional media input device by ID. */
|
|
@@ -14028,7 +14120,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14028
14120
|
*/
|
|
14029
14121
|
exitStudioModeIfActive() {
|
|
14030
14122
|
if (this._studioAudio$.value) {
|
|
14031
|
-
logger$
|
|
14123
|
+
logger$23.debug("[SelfParticipant] Exiting studio audio mode due to individual flag toggle");
|
|
14032
14124
|
this._studioAudio$.next(false);
|
|
14033
14125
|
}
|
|
14034
14126
|
}
|
|
@@ -14052,7 +14144,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14052
14144
|
try {
|
|
14053
14145
|
await super.mute();
|
|
14054
14146
|
} catch (error) {
|
|
14055
|
-
logger$
|
|
14147
|
+
logger$23.warn("[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway", error);
|
|
14056
14148
|
} finally {
|
|
14057
14149
|
this.vertoManager.muteMainAudioInputDevice();
|
|
14058
14150
|
}
|
|
@@ -14062,7 +14154,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14062
14154
|
try {
|
|
14063
14155
|
await super.unmute();
|
|
14064
14156
|
} catch (error) {
|
|
14065
|
-
logger$
|
|
14157
|
+
logger$23.warn("[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway", error);
|
|
14066
14158
|
} finally {
|
|
14067
14159
|
await this.vertoManager.unmuteMainAudioInputDevice();
|
|
14068
14160
|
}
|
|
@@ -14072,7 +14164,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14072
14164
|
try {
|
|
14073
14165
|
await super.muteVideo();
|
|
14074
14166
|
} catch (error) {
|
|
14075
|
-
logger$
|
|
14167
|
+
logger$23.warn("[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway", error);
|
|
14076
14168
|
} finally {
|
|
14077
14169
|
this.vertoManager.muteMainVideoInputDevice();
|
|
14078
14170
|
}
|
|
@@ -14082,7 +14174,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14082
14174
|
try {
|
|
14083
14175
|
await super.unmuteVideo();
|
|
14084
14176
|
} catch (error) {
|
|
14085
|
-
logger$
|
|
14177
|
+
logger$23.warn("[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway", error);
|
|
14086
14178
|
} finally {
|
|
14087
14179
|
await this.vertoManager.unmuteMainVideoInputDevice();
|
|
14088
14180
|
}
|
|
@@ -14176,7 +14268,7 @@ function isLayoutChangedPayload(value) {
|
|
|
14176
14268
|
|
|
14177
14269
|
//#endregion
|
|
14178
14270
|
//#region src/operators/filterNull.ts
|
|
14179
|
-
var import_cjs$
|
|
14271
|
+
var import_cjs$23 = require_cjs();
|
|
14180
14272
|
/**
|
|
14181
14273
|
* RxJS operator that filters out `null` and `undefined` values with type narrowing.
|
|
14182
14274
|
*
|
|
@@ -14188,7 +14280,7 @@ var import_cjs$21 = require_cjs();
|
|
|
14188
14280
|
* ```
|
|
14189
14281
|
*/
|
|
14190
14282
|
function filterNull() {
|
|
14191
|
-
return (0, import_cjs$
|
|
14283
|
+
return (0, import_cjs$23.filter)((value) => value != null);
|
|
14192
14284
|
}
|
|
14193
14285
|
|
|
14194
14286
|
//#endregion
|
|
@@ -14203,7 +14295,7 @@ const getValueFrom = (obj, path, defaultValue) => {
|
|
|
14203
14295
|
|
|
14204
14296
|
//#endregion
|
|
14205
14297
|
//#region src/operators/filterEventAs.ts
|
|
14206
|
-
var import_cjs$
|
|
14298
|
+
var import_cjs$22 = require_cjs();
|
|
14207
14299
|
var import_operators = require_operators();
|
|
14208
14300
|
/**
|
|
14209
14301
|
* RxJS operator that filters events based on a predicate and maps matching events.
|
|
@@ -14237,7 +14329,7 @@ var import_operators = require_operators();
|
|
|
14237
14329
|
* ```
|
|
14238
14330
|
*/
|
|
14239
14331
|
function ifIsMap(predicate, mapFn) {
|
|
14240
|
-
return (0, import_cjs$
|
|
14332
|
+
return (0, import_cjs$22.pipe)((0, import_operators.filter)(predicate), (0, import_operators.map)(mapFn));
|
|
14241
14333
|
}
|
|
14242
14334
|
/**
|
|
14243
14335
|
* Generic RxJS operator that filters events using a type guard and extracts a property.
|
|
@@ -14279,38 +14371,38 @@ function ifIsMap(predicate, mapFn) {
|
|
|
14279
14371
|
* ```
|
|
14280
14372
|
*/
|
|
14281
14373
|
function filterAs(predicate, resultPath) {
|
|
14282
|
-
return (0, import_cjs$
|
|
14374
|
+
return (0, import_cjs$22.pipe)(ifIsMap(predicate, (event) => {
|
|
14283
14375
|
return getValueFrom(event, resultPath);
|
|
14284
14376
|
}), (0, import_operators.filter)((value) => value !== void 0));
|
|
14285
14377
|
}
|
|
14286
14378
|
|
|
14287
14379
|
//#endregion
|
|
14288
14380
|
//#region src/operators/throwOnRPCError.ts
|
|
14289
|
-
var import_cjs$
|
|
14290
|
-
const logger$
|
|
14381
|
+
var import_cjs$21 = require_cjs();
|
|
14382
|
+
const logger$22 = getLogger();
|
|
14291
14383
|
/**
|
|
14292
14384
|
* RxJS operator that throws a {@link JSONRPCError} when the RPC response contains an error.
|
|
14293
14385
|
* Passes successful responses through unchanged.
|
|
14294
14386
|
*/
|
|
14295
14387
|
function throwOnRPCError() {
|
|
14296
|
-
return (0, import_cjs$
|
|
14388
|
+
return (0, import_cjs$21.map)((response) => {
|
|
14297
14389
|
if (response.error) {
|
|
14298
|
-
logger$
|
|
14390
|
+
logger$22.error("[throwOnRPCError] RPC error response:", {
|
|
14299
14391
|
code: response.error.code,
|
|
14300
14392
|
message: response.error.message,
|
|
14301
14393
|
data: response.error.data
|
|
14302
14394
|
});
|
|
14303
14395
|
throw new JSONRPCError(response.error.code, response.error.message, response.error.data);
|
|
14304
14396
|
}
|
|
14305
|
-
logger$
|
|
14397
|
+
logger$22.debug("[throwOnRPCError] RPC successful response:", response);
|
|
14306
14398
|
return response;
|
|
14307
14399
|
});
|
|
14308
14400
|
}
|
|
14309
14401
|
|
|
14310
14402
|
//#endregion
|
|
14311
14403
|
//#region src/managers/CallEventsManager.ts
|
|
14312
|
-
var import_cjs$
|
|
14313
|
-
const logger$
|
|
14404
|
+
var import_cjs$20 = require_cjs();
|
|
14405
|
+
const logger$21 = getLogger();
|
|
14314
14406
|
const initialSessionState = {};
|
|
14315
14407
|
/** @internal */
|
|
14316
14408
|
var CallEventsManager = class extends Destroyable {
|
|
@@ -14326,7 +14418,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14326
14418
|
this.initSubscriptions();
|
|
14327
14419
|
}
|
|
14328
14420
|
get participants$() {
|
|
14329
|
-
return this.cachedObservable("participants$", () => this._participants$.asObservable().pipe((0, import_cjs$
|
|
14421
|
+
return this.cachedObservable("participants$", () => this._participants$.asObservable().pipe((0, import_cjs$20.map)((participantsRecord) => Object.values(participantsRecord))));
|
|
14330
14422
|
}
|
|
14331
14423
|
get participants() {
|
|
14332
14424
|
return Object.values(this._participants$.value);
|
|
@@ -14344,40 +14436,40 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14344
14436
|
return this.callIds.has(callId);
|
|
14345
14437
|
}
|
|
14346
14438
|
get recording$() {
|
|
14347
|
-
return this.cachedObservable("recording$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14439
|
+
return this.cachedObservable("recording$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.recording), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14348
14440
|
}
|
|
14349
14441
|
get recordings$() {
|
|
14350
|
-
return this.cachedObservable("recordings$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14442
|
+
return this.cachedObservable("recordings$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.recordings), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14351
14443
|
}
|
|
14352
14444
|
get streaming$() {
|
|
14353
|
-
return this.cachedObservable("streaming$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14445
|
+
return this.cachedObservable("streaming$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.streaming), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14354
14446
|
}
|
|
14355
14447
|
get streams$() {
|
|
14356
|
-
return this.cachedObservable("streams$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14448
|
+
return this.cachedObservable("streams$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.streams), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14357
14449
|
}
|
|
14358
14450
|
get playbacks$() {
|
|
14359
|
-
return this.cachedObservable("playbacks$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14451
|
+
return this.cachedObservable("playbacks$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.playbacks), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14360
14452
|
}
|
|
14361
14453
|
get raiseHandPriority$() {
|
|
14362
|
-
return this.cachedObservable("raiseHandPriority$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14454
|
+
return this.cachedObservable("raiseHandPriority$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.prioritize_handraise), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14363
14455
|
}
|
|
14364
14456
|
get locked$() {
|
|
14365
|
-
return this.cachedObservable("locked$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14457
|
+
return this.cachedObservable("locked$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.locked), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14366
14458
|
}
|
|
14367
14459
|
get meta$() {
|
|
14368
|
-
return this.cachedObservable("meta$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14460
|
+
return this.cachedObservable("meta$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.meta), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14369
14461
|
}
|
|
14370
14462
|
get capabilities$() {
|
|
14371
|
-
return this.cachedObservable("capabilities$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14463
|
+
return this.cachedObservable("capabilities$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.capabilities), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14372
14464
|
}
|
|
14373
14465
|
get layout$() {
|
|
14374
|
-
return this.cachedObservable("layout$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14466
|
+
return this.cachedObservable("layout$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.layout_name), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14375
14467
|
}
|
|
14376
14468
|
get layouts$() {
|
|
14377
|
-
return this.cachedObservable("layouts$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14469
|
+
return this.cachedObservable("layouts$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.layouts), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14378
14470
|
}
|
|
14379
14471
|
get layoutLayers$() {
|
|
14380
|
-
return this.cachedObservable("layoutLayers$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14472
|
+
return this.cachedObservable("layoutLayers$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.layout_layers), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14381
14473
|
}
|
|
14382
14474
|
get self() {
|
|
14383
14475
|
return this._self$.value;
|
|
@@ -14414,7 +14506,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14414
14506
|
}
|
|
14415
14507
|
initSubscriptions() {
|
|
14416
14508
|
this.subscribeTo(this.callJoinedEvent$, (callJoinedEvent) => {
|
|
14417
|
-
logger$
|
|
14509
|
+
logger$21.debug("[CallEventsManager] Handling call.joined event for call/session IDs:", {
|
|
14418
14510
|
callId: callJoinedEvent.call_id,
|
|
14419
14511
|
roomSessionId: callJoinedEvent.room_session_id
|
|
14420
14512
|
});
|
|
@@ -14441,19 +14533,19 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14441
14533
|
if (this._self$.value?.capabilities.setLayout) this.updateLayouts();
|
|
14442
14534
|
});
|
|
14443
14535
|
this.subscribeTo(this.memberUpdates$, (member) => {
|
|
14444
|
-
logger$
|
|
14536
|
+
logger$21.debug("[CallEventsManager] Handling member update event for member ID:", member);
|
|
14445
14537
|
this.upsertParticipant(member);
|
|
14446
14538
|
});
|
|
14447
14539
|
this.subscribeTo(this.webRtcCallSession.memberLeft$, (memberLeftEvent) => {
|
|
14448
|
-
logger$
|
|
14540
|
+
logger$21.debug("[CallEventsManager] Handling member.left event for member ID:", memberLeftEvent.member.member_id);
|
|
14449
14541
|
const participants = { ...this._participants$.value };
|
|
14450
14542
|
if (memberLeftEvent.member.member_id in participants) {
|
|
14451
14543
|
delete participants[memberLeftEvent.member.member_id];
|
|
14452
14544
|
this._participants$.next(participants);
|
|
14453
|
-
} else logger$
|
|
14545
|
+
} else logger$21.warn(`[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`);
|
|
14454
14546
|
});
|
|
14455
14547
|
this.subscribeTo(this.webRtcCallSession.callUpdated$, (callUpdatedEvent) => {
|
|
14456
|
-
logger$
|
|
14548
|
+
logger$21.debug("[CallEventsManager] Handling call.updated event:", callUpdatedEvent);
|
|
14457
14549
|
const roomSession = callUpdatedEvent.room_session;
|
|
14458
14550
|
this._sessionState$.next({
|
|
14459
14551
|
...this._sessionState$.value,
|
|
@@ -14468,7 +14560,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14468
14560
|
});
|
|
14469
14561
|
});
|
|
14470
14562
|
this.subscribeTo(this.layoutChangedEvent$, (layoutChangedEvent) => {
|
|
14471
|
-
logger$
|
|
14563
|
+
logger$21.debug("[CallEventsManager] Handling layout.changed event:", layoutChangedEvent);
|
|
14472
14564
|
this._sessionState$.next({
|
|
14473
14565
|
...this._sessionState$.value,
|
|
14474
14566
|
layout_name: layoutChangedEvent.id,
|
|
@@ -14478,10 +14570,10 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14478
14570
|
});
|
|
14479
14571
|
}
|
|
14480
14572
|
updateParticipantPositions(layoutChangedEvent) {
|
|
14481
|
-
if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$
|
|
14573
|
+
if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$21.warn("[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.");
|
|
14482
14574
|
layoutChangedEvent.layers.filter((layer) => !!layer.member_id).filter((layer) => {
|
|
14483
14575
|
if (!(layer.member_id in this._participants$.value)) {
|
|
14484
|
-
logger$
|
|
14576
|
+
logger$21.warn(`[CallEventsManager] Skipping layout layer for unknown member_id: ${layer.member_id}`);
|
|
14485
14577
|
return false;
|
|
14486
14578
|
}
|
|
14487
14579
|
return true;
|
|
@@ -14504,7 +14596,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14504
14596
|
layouts: response.result.layouts
|
|
14505
14597
|
});
|
|
14506
14598
|
}).catch((error) => {
|
|
14507
|
-
logger$
|
|
14599
|
+
logger$21.error("[CallEventsManager] Error fetching layouts:", error);
|
|
14508
14600
|
});
|
|
14509
14601
|
}
|
|
14510
14602
|
updateParticipants(members) {
|
|
@@ -14520,7 +14612,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14520
14612
|
}
|
|
14521
14613
|
const participant = this._participants$.value[member.member_id];
|
|
14522
14614
|
const oldValue = participant.value;
|
|
14523
|
-
logger$
|
|
14615
|
+
logger$21.debug("[CallEventsManager] Updating participant:", member.member_id, {
|
|
14524
14616
|
oldValue,
|
|
14525
14617
|
newValue: member
|
|
14526
14618
|
});
|
|
@@ -14532,18 +14624,18 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14532
14624
|
this._participants$.next(this._participants$.value);
|
|
14533
14625
|
}
|
|
14534
14626
|
get callJoinedEvent$() {
|
|
14535
|
-
return this.cachedObservable("callJoinedEvent$", () => this.webRtcCallSession.callEvent$.pipe((0, import_cjs$
|
|
14536
|
-
logger$
|
|
14627
|
+
return this.cachedObservable("callJoinedEvent$", () => this.webRtcCallSession.callEvent$.pipe((0, import_cjs$20.filter)(isCallJoinedPayload), (0, import_cjs$20.tap)((event) => {
|
|
14628
|
+
logger$21.debug("[CallEventsManager] Call joined event:", event);
|
|
14537
14629
|
})));
|
|
14538
14630
|
}
|
|
14539
14631
|
get layoutChangedEvent$() {
|
|
14540
|
-
return this.cachedObservable("layoutChangedEvent$", () => this.webRtcCallSession.callEvent$.pipe(filterAs(isLayoutChangedPayload, "layout"), (0, import_cjs$
|
|
14541
|
-
logger$
|
|
14632
|
+
return this.cachedObservable("layoutChangedEvent$", () => this.webRtcCallSession.callEvent$.pipe(filterAs(isLayoutChangedPayload, "layout"), (0, import_cjs$20.tap)((event) => {
|
|
14633
|
+
logger$21.debug("[CallEventsManager] Layout changed event:", event);
|
|
14542
14634
|
})));
|
|
14543
14635
|
}
|
|
14544
14636
|
get memberUpdates$() {
|
|
14545
|
-
return this.cachedObservable("memberUpdates$", () => (0, import_cjs$
|
|
14546
|
-
logger$
|
|
14637
|
+
return this.cachedObservable("memberUpdates$", () => (0, import_cjs$20.merge)(this.webRtcCallSession.memberJoined$, this.webRtcCallSession.memberUpdated$, this.webRtcCallSession.memberTalking$).pipe((0, import_cjs$20.map)((event) => event.member), (0, import_cjs$20.tap)((event) => {
|
|
14638
|
+
logger$21.debug("[CallEventsManager] Member update event:", event);
|
|
14547
14639
|
})));
|
|
14548
14640
|
}
|
|
14549
14641
|
destroy() {
|
|
@@ -14799,8 +14891,8 @@ function appendStereoParams(fmtpLine, maxBitrate) {
|
|
|
14799
14891
|
|
|
14800
14892
|
//#endregion
|
|
14801
14893
|
//#region src/controllers/ICEGatheringController.ts
|
|
14802
|
-
var import_cjs$
|
|
14803
|
-
const logger$
|
|
14894
|
+
var import_cjs$19 = require_cjs();
|
|
14895
|
+
const logger$20 = getLogger();
|
|
14804
14896
|
var ICEGatheringController = class extends Destroyable {
|
|
14805
14897
|
constructor(peerConnection, peerConnectionControllerNegotiating$, options = {}) {
|
|
14806
14898
|
super();
|
|
@@ -14808,23 +14900,23 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14808
14900
|
this.peerConnectionControllerNegotiating$ = peerConnectionControllerNegotiating$;
|
|
14809
14901
|
this.onicegatheringstatechangeHandler = () => {
|
|
14810
14902
|
const { iceGatheringState } = this.peerConnection;
|
|
14811
|
-
logger$
|
|
14903
|
+
logger$20.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);
|
|
14812
14904
|
if (iceGatheringState === "gathering") this._iceCandidatesState.next({
|
|
14813
14905
|
state: "gathering",
|
|
14814
14906
|
validSDP: false
|
|
14815
14907
|
});
|
|
14816
14908
|
};
|
|
14817
14909
|
this.onicecandidateHandler = (event) => {
|
|
14818
|
-
logger$
|
|
14910
|
+
logger$20.debug("[ICEGatheringController] ICE candidate event received:", event.candidate);
|
|
14819
14911
|
this.removeTimer("iceCandidateTimer");
|
|
14820
14912
|
if (event.candidate) this.iceCandidateTimer = setTimeout(() => {
|
|
14821
14913
|
if (this.peerConnection.iceGatheringState !== "complete") {
|
|
14822
|
-
logger$
|
|
14914
|
+
logger$20.warn("[ICEGatheringController] ICE candidate timeout, using current SDP");
|
|
14823
14915
|
this.handleICECandidateTimeout();
|
|
14824
14916
|
}
|
|
14825
14917
|
}, this.iceCandidateTimeout);
|
|
14826
14918
|
else {
|
|
14827
|
-
logger$
|
|
14919
|
+
logger$20.debug("[ICEGatheringController] ICE gathering completed: null candidate received");
|
|
14828
14920
|
this.removeTimer("iceGatheringTimer");
|
|
14829
14921
|
this.handleICEGatheringComplete();
|
|
14830
14922
|
}
|
|
@@ -14837,12 +14929,12 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14837
14929
|
this.iceGatheringTimeout = options.iceGatheringTimeout ?? DEFAULT_ICE_GATHERING_TIMEOUT_MS;
|
|
14838
14930
|
this.relayOnly = options.relayOnly ?? false;
|
|
14839
14931
|
this.setupEventListeners();
|
|
14840
|
-
this.subscribeTo(this.peerConnectionControllerNegotiating$.pipe((0, import_cjs$
|
|
14932
|
+
this.subscribeTo(this.peerConnectionControllerNegotiating$.pipe((0, import_cjs$19.filter)((isNegotiating) => isNegotiating)), (isNegotiating) => {
|
|
14841
14933
|
if (isNegotiating) {
|
|
14842
14934
|
this.setupEventListeners();
|
|
14843
14935
|
this.iceGatheringTimer = setTimeout(() => {
|
|
14844
14936
|
if (this.peerConnection.iceGatheringState !== "complete") {
|
|
14845
|
-
logger$
|
|
14937
|
+
logger$20.warn("[ICEGatheringController] ICE gathering timeout, using current SDP");
|
|
14846
14938
|
this.handleICEGatheringTimeout();
|
|
14847
14939
|
}
|
|
14848
14940
|
}, this.iceGatheringTimeout);
|
|
@@ -14856,7 +14948,7 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14856
14948
|
this.peerConnection.addEventListener("icegatheringstatechange", this.onicegatheringstatechangeHandler);
|
|
14857
14949
|
}
|
|
14858
14950
|
get iceCandidatesState$() {
|
|
14859
|
-
return this._iceCandidatesState.pipe((0, import_cjs$
|
|
14951
|
+
return this._iceCandidatesState.pipe((0, import_cjs$19.withLatestFrom)(this.peerConnectionControllerNegotiating$), (0, import_cjs$19.filter)(([_, isNegotiating]) => isNegotiating), (0, import_cjs$19.map)(([state, _]) => state.state));
|
|
14860
14952
|
}
|
|
14861
14953
|
get hasValidLocalDescriptionSDP() {
|
|
14862
14954
|
const sdp = this.peerConnection.localDescription?.sdp;
|
|
@@ -14869,9 +14961,9 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14869
14961
|
this.relayOnly = value;
|
|
14870
14962
|
}
|
|
14871
14963
|
handleICEGatheringComplete() {
|
|
14872
|
-
logger$
|
|
14873
|
-
logger$
|
|
14874
|
-
logger$
|
|
14964
|
+
logger$20.debug("[ICEGatheringController] Handling ICE gathering complete");
|
|
14965
|
+
logger$20.debug(`[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`);
|
|
14966
|
+
logger$20.debug("[ICEGatheringController] ICE gathering complete");
|
|
14875
14967
|
this._iceCandidatesState.next({
|
|
14876
14968
|
state: "complete",
|
|
14877
14969
|
validSDP: this.hasValidLocalDescriptionSDP
|
|
@@ -14887,21 +14979,21 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14887
14979
|
this.removeTimer("iceGatheringTimer");
|
|
14888
14980
|
const validSDP = this.hasValidLocalDescriptionSDP;
|
|
14889
14981
|
if (validSDP) {
|
|
14890
|
-
logger$
|
|
14982
|
+
logger$20.debug("[ICEGatheringController] Local SDP is valid");
|
|
14891
14983
|
this._iceCandidatesState.next({
|
|
14892
14984
|
state: "timeout",
|
|
14893
14985
|
validSDP
|
|
14894
14986
|
});
|
|
14895
14987
|
this.stopGathering();
|
|
14896
|
-
} else logger$
|
|
14988
|
+
} else logger$20.debug("### ICE gathering timeout\n", this.peerConnection.localDescription?.sdp);
|
|
14897
14989
|
}
|
|
14898
14990
|
handleICECandidateTimeout() {
|
|
14899
14991
|
if (this.iceCandidateTimer) this.removeTimer("iceCandidateTimer");
|
|
14900
|
-
logger$
|
|
14992
|
+
logger$20.warn("[ICEGatheringController] ICE candidate timeout");
|
|
14901
14993
|
const validSDP = this.hasValidLocalDescriptionSDP;
|
|
14902
14994
|
if (!validSDP && !this.relayOnly) this.restartICEGatheringWithRelayOnly();
|
|
14903
14995
|
else {
|
|
14904
|
-
logger$
|
|
14996
|
+
logger$20.debug("[ICEGatheringController] Using current SDP due to ICE candidate timeout");
|
|
14905
14997
|
this._iceCandidatesState.next({
|
|
14906
14998
|
state: "timeout",
|
|
14907
14999
|
validSDP
|
|
@@ -14910,22 +15002,22 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14910
15002
|
}
|
|
14911
15003
|
}
|
|
14912
15004
|
restartICEGatheringWithRelayOnly() {
|
|
14913
|
-
logger$
|
|
15005
|
+
logger$20.debug("[ICEGatheringController] Restarting ICE gathering with relay-only candidates");
|
|
14914
15006
|
this.relayOnly = true;
|
|
14915
15007
|
this.peerConnection.setConfiguration({
|
|
14916
15008
|
...this.peerConnection.getConfiguration(),
|
|
14917
15009
|
iceTransportPolicy: "relay"
|
|
14918
15010
|
});
|
|
14919
|
-
|
|
15011
|
+
this.peerConnection.restartIce();
|
|
14920
15012
|
}
|
|
14921
|
-
removeTimer(timer$
|
|
14922
|
-
if (this[timer$
|
|
14923
|
-
clearTimeout(this[timer$
|
|
14924
|
-
this[timer$
|
|
15013
|
+
removeTimer(timer$4) {
|
|
15014
|
+
if (this[timer$4]) {
|
|
15015
|
+
clearTimeout(this[timer$4]);
|
|
15016
|
+
this[timer$4] = void 0;
|
|
14925
15017
|
}
|
|
14926
15018
|
}
|
|
14927
15019
|
clearAllTimers() {
|
|
14928
|
-
logger$
|
|
15020
|
+
logger$20.debug("[ICEGatheringController] Clearing all timers");
|
|
14929
15021
|
this.removeTimer("iceGatheringTimer");
|
|
14930
15022
|
this.removeTimer("iceCandidateTimer");
|
|
14931
15023
|
}
|
|
@@ -14934,17 +15026,181 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14934
15026
|
this.peerConnection.removeEventListener("icecandidate", this.onicecandidateHandler);
|
|
14935
15027
|
}
|
|
14936
15028
|
destroy() {
|
|
14937
|
-
logger$
|
|
15029
|
+
logger$20.debug("[ICEGatheringController] Destroying ICEGatheringController");
|
|
14938
15030
|
this.clearAllTimers();
|
|
14939
15031
|
this.removeEventListeners();
|
|
14940
15032
|
super.destroy();
|
|
14941
15033
|
}
|
|
14942
15034
|
};
|
|
14943
15035
|
|
|
15036
|
+
//#endregion
|
|
15037
|
+
//#region src/controllers/LocalAudioPipeline.ts
|
|
15038
|
+
var import_cjs$18 = require_cjs();
|
|
15039
|
+
const logger$19 = getLogger();
|
|
15040
|
+
/**
|
|
15041
|
+
* Web Audio pipeline for the local microphone stream.
|
|
15042
|
+
*
|
|
15043
|
+
* Wraps the raw mic `MediaStreamTrack` in a graph of:
|
|
15044
|
+
*
|
|
15045
|
+
* ```
|
|
15046
|
+
* MediaStreamAudioSourceNode → GainNode → AnalyserNode → MediaStreamAudioDestinationNode
|
|
15047
|
+
* ```
|
|
15048
|
+
*
|
|
15049
|
+
* The {@link outputTrack} from the destination node is what callers should
|
|
15050
|
+
* attach to the `RTCRtpSender` in place of the raw mic track. The same
|
|
15051
|
+
* destination track is reused across input changes (device switch, mute /
|
|
15052
|
+
* unmute track replacement) so the sender reference stays stable — only the
|
|
15053
|
+
* source end of the graph is rebuilt.
|
|
15054
|
+
*
|
|
15055
|
+
* The pipeline owns a single {@link AudioContext}. Callers must invoke
|
|
15056
|
+
* {@link destroy} to release it when the call ends.
|
|
15057
|
+
*/
|
|
15058
|
+
var LocalAudioPipeline = class extends Destroyable {
|
|
15059
|
+
constructor(options = {}) {
|
|
15060
|
+
super();
|
|
15061
|
+
this._inputSource = null;
|
|
15062
|
+
this._inputStream = null;
|
|
15063
|
+
this._lastSpokeAt = 0;
|
|
15064
|
+
this._gain$ = this.createBehaviorSubject(1);
|
|
15065
|
+
this._pttMultiplier = 1;
|
|
15066
|
+
this._audioContext = (options.audioContextFactory ?? (() => new AudioContext()))();
|
|
15067
|
+
this._gainNode = this._audioContext.createGain();
|
|
15068
|
+
this._analyser = this._audioContext.createAnalyser();
|
|
15069
|
+
this._analyser.fftSize = 2048;
|
|
15070
|
+
this._analyser.smoothingTimeConstant = .3;
|
|
15071
|
+
this._analyserBuffer = new Uint8Array(new ArrayBuffer(this._analyser.fftSize));
|
|
15072
|
+
this._destination = this._audioContext.createMediaStreamDestination();
|
|
15073
|
+
this._gainNode.connect(this._analyser);
|
|
15074
|
+
this._analyser.connect(this._destination);
|
|
15075
|
+
this._speakingThreshold = options.speakingThreshold ?? VAD_THRESHOLD;
|
|
15076
|
+
this._speakingHoldMs = options.speakingHoldMs ?? VAD_HOLD_MS;
|
|
15077
|
+
this._pollIntervalMs = options.pollIntervalMs ?? AUDIO_LEVEL_POLL_INTERVAL_MS;
|
|
15078
|
+
const initial = options.initialGain ?? 1;
|
|
15079
|
+
this._gain$.next(initial);
|
|
15080
|
+
this.applyEffectiveGain();
|
|
15081
|
+
}
|
|
15082
|
+
/** Observable of the current gain value (0..2). */
|
|
15083
|
+
get gain$() {
|
|
15084
|
+
return this._gain$.asObservable();
|
|
15085
|
+
}
|
|
15086
|
+
/** Current gain value (0..2). */
|
|
15087
|
+
get gain() {
|
|
15088
|
+
return this._gain$.value;
|
|
15089
|
+
}
|
|
15090
|
+
/**
|
|
15091
|
+
* Processed output track to attach to the RTCRtpSender. Stable reference
|
|
15092
|
+
* across input changes, so `sender.replaceTrack(pipeline.outputTrack)` only
|
|
15093
|
+
* needs to be called once.
|
|
15094
|
+
*/
|
|
15095
|
+
get outputTrack() {
|
|
15096
|
+
const [track] = this._destination.stream.getAudioTracks();
|
|
15097
|
+
return track;
|
|
15098
|
+
}
|
|
15099
|
+
/**
|
|
15100
|
+
* Root-mean-square audio level of the input signal, 0..1. Emits on a fixed
|
|
15101
|
+
* interval (~30fps by default).
|
|
15102
|
+
*/
|
|
15103
|
+
get level$() {
|
|
15104
|
+
return this.deferEmission((0, import_cjs$18.interval)(this._pollIntervalMs, import_cjs$18.animationFrameScheduler).pipe((0, import_cjs$18.map)(() => this.computeLevel())));
|
|
15105
|
+
}
|
|
15106
|
+
/**
|
|
15107
|
+
* Boolean VAD derived from {@link level$}. True while level ≥ threshold or
|
|
15108
|
+
* during the hold window after the last frame that crossed the threshold.
|
|
15109
|
+
*/
|
|
15110
|
+
get speaking$() {
|
|
15111
|
+
return this.deferEmission(this.level$.pipe((0, import_cjs$18.map)((level) => this.evaluateSpeaking(level)), (0, import_cjs$18.distinctUntilChanged)()));
|
|
15112
|
+
}
|
|
15113
|
+
/**
|
|
15114
|
+
* Set gain multiplier applied to the input signal. 0 = silence,
|
|
15115
|
+
* 1 = unity, 2 = 2x. Values are clamped to [0, 2]. The effective gain on
|
|
15116
|
+
* the graph also respects the current PTT state.
|
|
15117
|
+
*/
|
|
15118
|
+
setGain(value) {
|
|
15119
|
+
const clamped = Math.max(0, Math.min(2, value));
|
|
15120
|
+
this._gain$.next(clamped);
|
|
15121
|
+
this.applyEffectiveGain();
|
|
15122
|
+
}
|
|
15123
|
+
/**
|
|
15124
|
+
* Silence the graph when `active = false`, otherwise restore the configured
|
|
15125
|
+
* gain. Use this from a PTT handler: released → `false`, held → `true`.
|
|
15126
|
+
* Orthogonal to {@link setGain} — once PTT returns to active, the last
|
|
15127
|
+
* configured gain reappears.
|
|
15128
|
+
*/
|
|
15129
|
+
setPTTActive(active) {
|
|
15130
|
+
this._pttMultiplier = active ? 1 : 0;
|
|
15131
|
+
this.applyEffectiveGain();
|
|
15132
|
+
}
|
|
15133
|
+
applyEffectiveGain() {
|
|
15134
|
+
this._gainNode.gain.value = this._gain$.value * this._pttMultiplier;
|
|
15135
|
+
}
|
|
15136
|
+
/**
|
|
15137
|
+
* Wire a new raw mic track as the pipeline's input. Replaces any previous
|
|
15138
|
+
* input source and reconnects the graph so {@link outputTrack} continues
|
|
15139
|
+
* to emit the processed audio. Pass `null` to disconnect the input (the
|
|
15140
|
+
* output track stays alive but emits silence).
|
|
15141
|
+
*
|
|
15142
|
+
* Also resumes the underlying AudioContext on attach — Chrome creates it
|
|
15143
|
+
* in a suspended state and the graph won't process (the destination
|
|
15144
|
+
* track emits silence) until resume() succeeds.
|
|
15145
|
+
*/
|
|
15146
|
+
setInputTrack(track) {
|
|
15147
|
+
if (this._inputSource) {
|
|
15148
|
+
try {
|
|
15149
|
+
this._inputSource.disconnect();
|
|
15150
|
+
} catch (error) {
|
|
15151
|
+
logger$19.debug("[LocalAudioPipeline] input disconnect warning:", error);
|
|
15152
|
+
}
|
|
15153
|
+
this._inputSource = null;
|
|
15154
|
+
}
|
|
15155
|
+
if (this._inputStream) this._inputStream = null;
|
|
15156
|
+
if (!track) return;
|
|
15157
|
+
this._inputStream = new MediaStream([track]);
|
|
15158
|
+
this._inputSource = this._audioContext.createMediaStreamSource(this._inputStream);
|
|
15159
|
+
this._inputSource.connect(this._gainNode);
|
|
15160
|
+
if (this._audioContext.state === "suspended") this._audioContext.resume().catch((error) => {
|
|
15161
|
+
logger$19.warn("[LocalAudioPipeline] AudioContext resume failed:", error);
|
|
15162
|
+
});
|
|
15163
|
+
}
|
|
15164
|
+
destroy() {
|
|
15165
|
+
if (this._inputSource) {
|
|
15166
|
+
try {
|
|
15167
|
+
this._inputSource.disconnect();
|
|
15168
|
+
} catch {}
|
|
15169
|
+
this._inputSource = null;
|
|
15170
|
+
}
|
|
15171
|
+
try {
|
|
15172
|
+
this._gainNode.disconnect();
|
|
15173
|
+
this._analyser.disconnect();
|
|
15174
|
+
} catch {}
|
|
15175
|
+
this._audioContext.close().catch((error) => {
|
|
15176
|
+
logger$19.debug("[LocalAudioPipeline] audio context close warning:", error);
|
|
15177
|
+
});
|
|
15178
|
+
super.destroy();
|
|
15179
|
+
}
|
|
15180
|
+
computeLevel() {
|
|
15181
|
+
if (!this._inputSource) return 0;
|
|
15182
|
+
this._analyser.getByteTimeDomainData(this._analyserBuffer);
|
|
15183
|
+
let sum = 0;
|
|
15184
|
+
for (const sample$1 of this._analyserBuffer) {
|
|
15185
|
+
const normalized = (sample$1 - 128) / 128;
|
|
15186
|
+
sum += normalized * normalized;
|
|
15187
|
+
}
|
|
15188
|
+
return Math.sqrt(sum / this._analyserBuffer.length);
|
|
15189
|
+
}
|
|
15190
|
+
evaluateSpeaking(level) {
|
|
15191
|
+
const now = Date.now();
|
|
15192
|
+
if (level >= this._speakingThreshold) {
|
|
15193
|
+
this._lastSpokeAt = now;
|
|
15194
|
+
return true;
|
|
15195
|
+
}
|
|
15196
|
+
return now - this._lastSpokeAt < this._speakingHoldMs;
|
|
15197
|
+
}
|
|
15198
|
+
};
|
|
15199
|
+
|
|
14944
15200
|
//#endregion
|
|
14945
15201
|
//#region src/controllers/LocalStreamController.ts
|
|
14946
|
-
var import_cjs$
|
|
14947
|
-
const logger$
|
|
15202
|
+
var import_cjs$17 = require_cjs();
|
|
15203
|
+
const logger$18 = getLogger();
|
|
14948
15204
|
var LocalStreamController = class extends Destroyable {
|
|
14949
15205
|
constructor(options) {
|
|
14950
15206
|
super();
|
|
@@ -14958,16 +15214,16 @@ var LocalStreamController = class extends Destroyable {
|
|
|
14958
15214
|
this._mediaTrackEnded$ = this.createSubject();
|
|
14959
15215
|
}
|
|
14960
15216
|
get localStream$() {
|
|
14961
|
-
return this._localStream$.asObservable().pipe((0, import_cjs$
|
|
15217
|
+
return this._localStream$.asObservable().pipe((0, import_cjs$17.takeUntil)(this.destroyed$));
|
|
14962
15218
|
}
|
|
14963
15219
|
get localAudioTracks$() {
|
|
14964
|
-
return this._localAudioTracks$.asObservable().pipe((0, import_cjs$
|
|
15220
|
+
return this._localAudioTracks$.asObservable().pipe((0, import_cjs$17.takeUntil)(this.destroyed$));
|
|
14965
15221
|
}
|
|
14966
15222
|
get localVideoTracks$() {
|
|
14967
|
-
return this._localVideoTracks$.asObservable().pipe((0, import_cjs$
|
|
15223
|
+
return this._localVideoTracks$.asObservable().pipe((0, import_cjs$17.takeUntil)(this.destroyed$));
|
|
14968
15224
|
}
|
|
14969
15225
|
get mediaTrackEnded$() {
|
|
14970
|
-
return this._mediaTrackEnded$.asObservable().pipe((0, import_cjs$
|
|
15226
|
+
return this._mediaTrackEnded$.asObservable().pipe((0, import_cjs$17.takeUntil)(this.destroyed$));
|
|
14971
15227
|
}
|
|
14972
15228
|
get localStream() {
|
|
14973
15229
|
return this._localStream$.value;
|
|
@@ -14982,26 +15238,26 @@ var LocalStreamController = class extends Destroyable {
|
|
|
14982
15238
|
* Build the local media stream based on the provided options.
|
|
14983
15239
|
*/
|
|
14984
15240
|
async buildLocalStream() {
|
|
14985
|
-
logger$
|
|
15241
|
+
logger$18.debug("[LocalStreamController] Building local media stream.");
|
|
14986
15242
|
let stream;
|
|
14987
15243
|
if (this.options.inputAudioStream ?? this.options.inputVideoStream) {
|
|
14988
15244
|
const tracks = [...this.options.inputAudioStream?.getTracks() ?? [], ...this.options.inputVideoStream?.getTracks() ?? []];
|
|
14989
15245
|
stream = new MediaStream(tracks);
|
|
14990
15246
|
} else if (this.options.propose === "screenshare") {
|
|
14991
|
-
logger$
|
|
15247
|
+
logger$18.debug("[LocalStreamController] Requesting display media for screen sharing with audio:", Boolean(this.options.inputAudioDeviceConstraints));
|
|
14992
15248
|
stream = await this.options.getDisplayMedia({
|
|
14993
15249
|
video: true,
|
|
14994
15250
|
audio: Boolean(this.options.inputAudioDeviceConstraints)
|
|
14995
15251
|
});
|
|
14996
|
-
logger$
|
|
15252
|
+
logger$18.debug("[LocalStreamController] Screen share media obtained:", stream);
|
|
14997
15253
|
} else {
|
|
14998
15254
|
const constraints = {
|
|
14999
15255
|
audio: this.options.inputAudioDeviceConstraints,
|
|
15000
15256
|
video: this.options.inputVideoDeviceConstraints
|
|
15001
15257
|
};
|
|
15002
|
-
logger$
|
|
15258
|
+
logger$18.debug("[LocalStreamController] Requesting user media with constraints:", constraints);
|
|
15003
15259
|
stream = await this.options.getUserMedia(constraints);
|
|
15004
|
-
logger$
|
|
15260
|
+
logger$18.debug("[LocalStreamController] User media obtained:", stream);
|
|
15005
15261
|
}
|
|
15006
15262
|
this._localStream$.next(stream);
|
|
15007
15263
|
return stream;
|
|
@@ -15018,7 +15274,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15018
15274
|
this._localStream$.next(localStream);
|
|
15019
15275
|
if (track.kind === "video") this._localVideoTracks$.next(localStream.getVideoTracks());
|
|
15020
15276
|
else this._localAudioTracks$.next(localStream.getAudioTracks());
|
|
15021
|
-
logger$
|
|
15277
|
+
logger$18.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);
|
|
15022
15278
|
return localStream;
|
|
15023
15279
|
}
|
|
15024
15280
|
/**
|
|
@@ -15030,7 +15286,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15030
15286
|
const stream = this._localStream$.value;
|
|
15031
15287
|
const track = stream?.getTracks().find((t) => t.id === trackId);
|
|
15032
15288
|
if (!track) {
|
|
15033
|
-
logger$
|
|
15289
|
+
logger$18.debug(`[LocalStreamController] track not found: ${trackId}`);
|
|
15034
15290
|
return;
|
|
15035
15291
|
}
|
|
15036
15292
|
track.removeEventListener("ended", this.mediaTrackEndedHandler);
|
|
@@ -15039,7 +15295,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15039
15295
|
this._localStream$.next(stream);
|
|
15040
15296
|
if (track.kind === "video") this._localVideoTracks$.next(stream?.getVideoTracks() ?? []);
|
|
15041
15297
|
else this._localAudioTracks$.next(stream?.getAudioTracks() ?? []);
|
|
15042
|
-
logger$
|
|
15298
|
+
logger$18.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);
|
|
15043
15299
|
return track;
|
|
15044
15300
|
}
|
|
15045
15301
|
/**
|
|
@@ -15074,7 +15330,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15074
15330
|
*/
|
|
15075
15331
|
stopAllTracks() {
|
|
15076
15332
|
this._localStream$.value?.getTracks().forEach((track) => {
|
|
15077
|
-
logger$
|
|
15333
|
+
logger$18.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);
|
|
15078
15334
|
track.removeEventListener("ended", this.mediaTrackEndedHandler);
|
|
15079
15335
|
track.stop();
|
|
15080
15336
|
});
|
|
@@ -15090,7 +15346,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15090
15346
|
|
|
15091
15347
|
//#endregion
|
|
15092
15348
|
//#region src/controllers/TransceiverController.ts
|
|
15093
|
-
const logger$
|
|
15349
|
+
const logger$17 = getLogger();
|
|
15094
15350
|
const getDirection = (send, recv) => {
|
|
15095
15351
|
if (send && recv) return "sendrecv";
|
|
15096
15352
|
else if (send && !recv) return "sendonly";
|
|
@@ -15192,7 +15448,7 @@ var TransceiverController = class extends Destroyable {
|
|
|
15192
15448
|
sendEncodings: isAudio ? void 0 : this.sendEncodings,
|
|
15193
15449
|
streams: direction === "recvonly" ? void 0 : [localStream]
|
|
15194
15450
|
};
|
|
15195
|
-
logger$
|
|
15451
|
+
logger$17.debug(`[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`, {
|
|
15196
15452
|
transceiver,
|
|
15197
15453
|
transceiverParams
|
|
15198
15454
|
});
|
|
@@ -15200,11 +15456,11 @@ var TransceiverController = class extends Destroyable {
|
|
|
15200
15456
|
await transceiver.sender.replaceTrack(track);
|
|
15201
15457
|
transceiver.direction = transceiverParams.direction;
|
|
15202
15458
|
if (transceiverParams.streams?.some((stream) => Boolean(stream))) {
|
|
15203
|
-
logger$
|
|
15459
|
+
logger$17.debug(`[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`, transceiverParams.streams);
|
|
15204
15460
|
transceiver.sender.setStreams(...transceiverParams.streams);
|
|
15205
15461
|
}
|
|
15206
15462
|
} else {
|
|
15207
|
-
logger$
|
|
15463
|
+
logger$17.debug(`[TransceiverController] Adding new transceiver for local ${track.kind} track:`, track.id);
|
|
15208
15464
|
this.peerConnection.addTransceiver(track, transceiverParams);
|
|
15209
15465
|
}
|
|
15210
15466
|
}
|
|
@@ -15218,13 +15474,13 @@ var TransceiverController = class extends Destroyable {
|
|
|
15218
15474
|
if (options.updateTransceiverDirection) transceiver.direction = "inactive";
|
|
15219
15475
|
}
|
|
15220
15476
|
} catch (error) {
|
|
15221
|
-
logger$
|
|
15477
|
+
logger$17.error("[TransceiverController] stopTrackSender error", kind, error);
|
|
15222
15478
|
this.options.onError?.(new MediaTrackError("stopTrackSender", kind, error));
|
|
15223
15479
|
}
|
|
15224
15480
|
}
|
|
15225
15481
|
async restoreTrackSender(kind) {
|
|
15226
15482
|
try {
|
|
15227
|
-
logger$
|
|
15483
|
+
logger$17.debug("[TransceiverController] restoreTrackSender called", kind);
|
|
15228
15484
|
const constraints = {};
|
|
15229
15485
|
const transceivers = this.transceiverByKind(kind);
|
|
15230
15486
|
for (const transceiver of transceivers) {
|
|
@@ -15234,23 +15490,23 @@ var TransceiverController = class extends Destroyable {
|
|
|
15234
15490
|
if (trackKind === "audio" || trackKind === "video") constraints[trackKind] = this.getConstraintsFor(trackKind);
|
|
15235
15491
|
}
|
|
15236
15492
|
}
|
|
15237
|
-
logger$
|
|
15493
|
+
logger$17.debug("[TransceiverController] restoreTrackSender constraints:", constraints);
|
|
15238
15494
|
if (Object.keys(constraints).length === 0) {
|
|
15239
|
-
logger$
|
|
15495
|
+
logger$17.warn("[TransceiverController] restoreTrackSender: no tracks need restoration", kind);
|
|
15240
15496
|
return;
|
|
15241
15497
|
}
|
|
15242
15498
|
const newTracks = (await this.options.getUserMedia(constraints)).getTracks();
|
|
15243
|
-
logger$
|
|
15499
|
+
logger$17.debug("[TransceiverController] restoreTrackSender new tracks:", newTracks);
|
|
15244
15500
|
for (const newTrack of newTracks) {
|
|
15245
15501
|
this.options.localStreamController.addTrack(newTrack);
|
|
15246
15502
|
const trackKind = newTrack.kind;
|
|
15247
15503
|
const transceiverOfKind = this.transceiverByKind(trackKind)[0];
|
|
15248
15504
|
transceiverOfKind.direction = trackKind === "audio" ? this.audioDirection : this.videoDirection;
|
|
15249
|
-
logger$
|
|
15505
|
+
logger$17.debug("[TransceiverController] restoreTrackSender setting direction for", trackKind, transceiverOfKind.direction);
|
|
15250
15506
|
await transceiverOfKind.sender.replaceTrack(newTrack);
|
|
15251
15507
|
}
|
|
15252
15508
|
} catch (error) {
|
|
15253
|
-
logger$
|
|
15509
|
+
logger$17.error("[TransceiverController] restoreTrackSender error", kind, error);
|
|
15254
15510
|
this.options.onError?.(new MediaTrackError("restoreTrackSender", kind, error));
|
|
15255
15511
|
}
|
|
15256
15512
|
}
|
|
@@ -15291,14 +15547,14 @@ var TransceiverController = class extends Destroyable {
|
|
|
15291
15547
|
};
|
|
15292
15548
|
try {
|
|
15293
15549
|
await track.applyConstraints(constraintsToApply);
|
|
15294
|
-
logger$
|
|
15295
|
-
logger$
|
|
15550
|
+
logger$17.debug(`[TransceiverController] Updated ${kind} sender constraints:`, constraintsToApply);
|
|
15551
|
+
logger$17.debug(`[TransceiverController] Updated ${kind} sender constraints:`, track.getConstraints());
|
|
15296
15552
|
} catch (error) {
|
|
15297
|
-
logger$
|
|
15553
|
+
logger$17.warn(`[TransceiverController] applyConstraints failed for ${kind} track ${track.id}, attempting track replacement fallback:`, error);
|
|
15298
15554
|
try {
|
|
15299
15555
|
await this.replaceTrackFallback(sender, track, kind, constraintsToApply);
|
|
15300
15556
|
} catch (fallbackError) {
|
|
15301
|
-
logger$
|
|
15557
|
+
logger$17.warn(`[TransceiverController] Track replacement fallback also failed for ${kind} track:`, fallbackError);
|
|
15302
15558
|
this.options.onError?.(new MediaTrackError("updateSendersConstraints", kind, fallbackError));
|
|
15303
15559
|
}
|
|
15304
15560
|
}
|
|
@@ -15326,7 +15582,7 @@ var TransceiverController = class extends Destroyable {
|
|
|
15326
15582
|
if (!newTrack) throw new MediaTrackError("replaceTrackFallback", kind, /* @__PURE__ */ new Error("getUserMedia returned no track of the requested kind"));
|
|
15327
15583
|
await sender.replaceTrack(newTrack);
|
|
15328
15584
|
this.options.localStreamController.addTrack(newTrack);
|
|
15329
|
-
logger$
|
|
15585
|
+
logger$17.debug(`[TransceiverController] Track replacement fallback succeeded for ${kind}. New track: ${newTrack.id}`);
|
|
15330
15586
|
}
|
|
15331
15587
|
getMediaDirections() {
|
|
15332
15588
|
if (this.peerConnection.connectionState === "connected") return this.peerConnection.getTransceivers().reduce((acc, transceiver) => {
|
|
@@ -15356,60 +15612,60 @@ var TransceiverController = class extends Destroyable {
|
|
|
15356
15612
|
|
|
15357
15613
|
//#endregion
|
|
15358
15614
|
//#region src/controllers/RTCPeerConnectionController.ts
|
|
15359
|
-
var import_cjs$
|
|
15360
|
-
const logger$
|
|
15615
|
+
var import_cjs$16 = require_cjs();
|
|
15616
|
+
const logger$16 = getLogger();
|
|
15361
15617
|
var RTCPeerConnectionController = class extends Destroyable {
|
|
15362
15618
|
constructor(options = {}, remoteSessionDescription, deviceController) {
|
|
15363
15619
|
super();
|
|
15364
15620
|
this.options = options;
|
|
15365
15621
|
this.firstSDPExchangeCompleted = false;
|
|
15366
15622
|
this.negotiationNeeded$ = this.createSubject();
|
|
15367
|
-
this.localDescription$ = (0, import_cjs$
|
|
15623
|
+
this.localDescription$ = (0, import_cjs$16.defer)(() => (0, import_cjs$16.from)(this.init())).pipe((0, import_cjs$16.switchMap)(() => this.iceGatheringController.iceCandidatesState$.pipe((0, import_cjs$16.filter)((iceCandidateState) => !["new", "gathering"].includes(iceCandidateState)), (0, import_cjs$16.tap)(() => {
|
|
15368
15624
|
this.negotiationEnded();
|
|
15369
|
-
}), (0, import_cjs$
|
|
15625
|
+
}), (0, import_cjs$16.filter)(() => this.shouldEmitLocalDescription), (0, import_cjs$16.map)(() => this.peerConnection?.localDescription), filterNull(), (0, import_cjs$16.tap)((desc) => {
|
|
15370
15626
|
if (desc.type === "answer") this._type = "offer";
|
|
15371
|
-
}))), (0, import_cjs$
|
|
15627
|
+
}))), (0, import_cjs$16.shareReplay)(1), (0, import_cjs$16.takeUntil)(this.destroyed$));
|
|
15372
15628
|
this.connectionTimeout = 3e3;
|
|
15373
15629
|
this.oniceconnectionstatechangeHandler = () => {
|
|
15374
15630
|
if (this.peerConnection) {
|
|
15375
15631
|
const { iceConnectionState } = this.peerConnection;
|
|
15376
|
-
logger$
|
|
15632
|
+
logger$16.debug(`[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`);
|
|
15377
15633
|
this._iceConnectionState$.next(this.peerConnection.iceConnectionState);
|
|
15378
15634
|
}
|
|
15379
15635
|
};
|
|
15380
15636
|
this.onconnectionstatechangeHandler = () => {
|
|
15381
15637
|
if (this.peerConnection) {
|
|
15382
15638
|
const { connectionState } = this.peerConnection;
|
|
15383
|
-
logger$
|
|
15639
|
+
logger$16.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);
|
|
15384
15640
|
if (connectionState === "connected") this.removeConnectionTimer();
|
|
15385
15641
|
this._connectionState$.next(this.peerConnection.connectionState);
|
|
15386
15642
|
}
|
|
15387
15643
|
};
|
|
15388
15644
|
this.onsignalingstatechangeHandler = () => {
|
|
15389
|
-
logger$
|
|
15645
|
+
logger$16.debug(`[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`);
|
|
15390
15646
|
};
|
|
15391
15647
|
this.onicegatheringstatechangeHandler = () => {
|
|
15392
15648
|
if (this.peerConnection) this._iceGatheringState$.next(this.peerConnection.iceGatheringState);
|
|
15393
15649
|
};
|
|
15394
15650
|
this.onnegotiationneededHandler = (event) => {
|
|
15395
|
-
logger$
|
|
15651
|
+
logger$16.debug("[RTCPeerConnectionController] Negotiation needed event received.", event);
|
|
15396
15652
|
this.negotiationNeeded$.next();
|
|
15397
15653
|
};
|
|
15398
15654
|
this.updateSelectedInputDevice = async (kind, deviceInfo) => {
|
|
15399
15655
|
try {
|
|
15400
15656
|
const { localStream } = this;
|
|
15401
15657
|
if (!localStream) {
|
|
15402
|
-
logger$
|
|
15658
|
+
logger$16.warn("[RTCPeerConnectionController] No local stream available to update input device.");
|
|
15403
15659
|
return;
|
|
15404
15660
|
}
|
|
15405
|
-
logger$
|
|
15661
|
+
logger$16.debug(`[RTCPeerConnectionController] Updating selected ${kind} input device:`, localStream.getTracks());
|
|
15406
15662
|
const track = localStream.getTracks().find((track$1) => track$1.kind === kind);
|
|
15407
15663
|
if (track) {
|
|
15408
15664
|
this.transceiverController?.stopTrackSender(kind);
|
|
15409
|
-
this.
|
|
15410
|
-
logger$
|
|
15665
|
+
this.localStreamController.removeTrack(track.id);
|
|
15666
|
+
logger$16.debug(`[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`, localStream.getTracks());
|
|
15411
15667
|
if (!deviceInfo) {
|
|
15412
|
-
logger$
|
|
15668
|
+
logger$16.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
|
|
15413
15669
|
return;
|
|
15414
15670
|
}
|
|
15415
15671
|
const streamTrack = (await this.getUserMedia({ [kind]: {
|
|
@@ -15417,15 +15673,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15417
15673
|
...this.deviceController.deviceInfoToConstraints(deviceInfo)
|
|
15418
15674
|
} })).getTracks().find((t) => t.kind === kind);
|
|
15419
15675
|
if (streamTrack) {
|
|
15420
|
-
logger$
|
|
15421
|
-
this.
|
|
15676
|
+
logger$16.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);
|
|
15677
|
+
this.localStreamController.addTrack(streamTrack);
|
|
15422
15678
|
await this.transceiverController?.replaceSenderTrack(kind, streamTrack);
|
|
15423
|
-
logger$
|
|
15679
|
+
logger$16.debug(`[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`, this.localStream?.getTracks());
|
|
15424
15680
|
}
|
|
15425
15681
|
}
|
|
15426
|
-
logger$
|
|
15682
|
+
logger$16.debug(`[RTCPeerConnectionController] ${kind} input device selected:`, deviceInfo?.label);
|
|
15427
15683
|
} catch (error) {
|
|
15428
|
-
logger$
|
|
15684
|
+
logger$16.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);
|
|
15429
15685
|
this._errors$.next(toError(error));
|
|
15430
15686
|
throw error;
|
|
15431
15687
|
}
|
|
@@ -15442,6 +15698,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15442
15698
|
this._remoteDescription$ = this.createReplaySubject(1);
|
|
15443
15699
|
this._remoteStream$ = this.createBehaviorSubject(null);
|
|
15444
15700
|
this._remoteOfferMediaDirections = null;
|
|
15701
|
+
this._localAudioPipeline = null;
|
|
15445
15702
|
this.deviceController = deviceController ?? {};
|
|
15446
15703
|
this.id = options.callId ?? v4_default();
|
|
15447
15704
|
this._type = remoteSessionDescription ? "answer" : "offer";
|
|
@@ -15511,43 +15768,43 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15511
15768
|
};
|
|
15512
15769
|
}
|
|
15513
15770
|
get iceGatheringState$() {
|
|
15514
|
-
return this.cachedObservable("iceGatheringState$", () => this._iceGatheringState$.asObservable().pipe((0, import_cjs$
|
|
15771
|
+
return this.cachedObservable("iceGatheringState$", () => this._iceGatheringState$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15515
15772
|
}
|
|
15516
15773
|
get mediaTrackEnded$() {
|
|
15517
|
-
return this.cachedObservable("mediaTrackEnded$", () => this.localStreamController.mediaTrackEnded$.pipe((0, import_cjs$
|
|
15774
|
+
return this.cachedObservable("mediaTrackEnded$", () => this.localStreamController.mediaTrackEnded$.pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15518
15775
|
}
|
|
15519
15776
|
get errors$() {
|
|
15520
|
-
return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$
|
|
15777
|
+
return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15521
15778
|
}
|
|
15522
15779
|
get iceCandidates$() {
|
|
15523
|
-
return this.cachedObservable("iceCandidates$", () => this._iceCandidates$.asObservable().pipe((0, import_cjs$
|
|
15780
|
+
return this.cachedObservable("iceCandidates$", () => this._iceCandidates$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15524
15781
|
}
|
|
15525
15782
|
get initialized$() {
|
|
15526
|
-
return this.cachedObservable("initialized$", () => this._initialized$.asObservable().pipe((0, import_cjs$
|
|
15783
|
+
return this.cachedObservable("initialized$", () => this._initialized$.asObservable().pipe((0, import_cjs$16.filter)((initialized) => initialized), (0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15527
15784
|
}
|
|
15528
15785
|
get remoteDescription$() {
|
|
15529
|
-
return this.cachedObservable("remoteDescription$", () => this._remoteDescription$.asObservable().pipe((0, import_cjs$
|
|
15786
|
+
return this.cachedObservable("remoteDescription$", () => this._remoteDescription$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15530
15787
|
}
|
|
15531
15788
|
get localStream$() {
|
|
15532
|
-
return this.cachedObservable("localStream$", () => this.localStreamController.localStream$.pipe((0, import_cjs$
|
|
15789
|
+
return this.cachedObservable("localStream$", () => this.localStreamController.localStream$.pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15533
15790
|
}
|
|
15534
15791
|
get remoteStream$() {
|
|
15535
|
-
return this.cachedObservable("remoteStream$", () => this._remoteStream$.asObservable().pipe((0, import_cjs$
|
|
15792
|
+
return this.cachedObservable("remoteStream$", () => this._remoteStream$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15536
15793
|
}
|
|
15537
15794
|
get localAudioTracks$() {
|
|
15538
|
-
return this.cachedObservable("localAudioTracks$", () => this.localStreamController.localAudioTracks$.pipe((0, import_cjs$
|
|
15795
|
+
return this.cachedObservable("localAudioTracks$", () => this.localStreamController.localAudioTracks$.pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15539
15796
|
}
|
|
15540
15797
|
get localVideoTracks$() {
|
|
15541
|
-
return this.cachedObservable("localVideoTracks$", () => this.localStreamController.localVideoTracks$.pipe((0, import_cjs$
|
|
15798
|
+
return this.cachedObservable("localVideoTracks$", () => this.localStreamController.localVideoTracks$.pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15542
15799
|
}
|
|
15543
15800
|
get iceConnectionState$() {
|
|
15544
|
-
return this.cachedObservable("iceConnectionState$", () => this._iceConnectionState$.asObservable().pipe((0, import_cjs$
|
|
15801
|
+
return this.cachedObservable("iceConnectionState$", () => this._iceConnectionState$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15545
15802
|
}
|
|
15546
15803
|
get connectionState$() {
|
|
15547
|
-
return this.cachedObservable("connectionState$", () => this._connectionState$.asObservable().pipe((0, import_cjs$
|
|
15804
|
+
return this.cachedObservable("connectionState$", () => this._connectionState$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15548
15805
|
}
|
|
15549
15806
|
get signalingState$() {
|
|
15550
|
-
return this.cachedObservable("signalingState$", () => this._signalingState$.asObservable().pipe((0, import_cjs$
|
|
15807
|
+
return this.cachedObservable("signalingState$", () => this._signalingState$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15551
15808
|
}
|
|
15552
15809
|
get type() {
|
|
15553
15810
|
return this._type;
|
|
@@ -15660,17 +15917,17 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15660
15917
|
async doInit() {
|
|
15661
15918
|
try {
|
|
15662
15919
|
this.setupPeerConnection();
|
|
15663
|
-
this.subscribeTo(this.negotiationNeeded$.pipe((0, import_cjs$
|
|
15920
|
+
this.subscribeTo(this.negotiationNeeded$.pipe((0, import_cjs$16.auditTime)(0), (0, import_cjs$16.exhaustMap)(async () => this.startNegotiation())), {
|
|
15664
15921
|
next: () => {
|
|
15665
|
-
logger$
|
|
15922
|
+
logger$16.debug("[RTCPeerConnectionController] Start Negotiation completed successfully");
|
|
15666
15923
|
},
|
|
15667
15924
|
error: (error) => {
|
|
15668
|
-
logger$
|
|
15925
|
+
logger$16.error("[RTCPeerConnectionController] Start Negotiation error:", error);
|
|
15669
15926
|
this._errors$.next(toError(error));
|
|
15670
15927
|
}
|
|
15671
15928
|
});
|
|
15672
|
-
this.subscribeTo((0, import_cjs$
|
|
15673
|
-
logger$
|
|
15929
|
+
this.subscribeTo((0, import_cjs$16.merge)(this.deviceController.selectedAudioInputDevice$.pipe((0, import_cjs$16.map)((deviceInfo) => ["audio", deviceInfo])), this.deviceController.selectedVideoInputDevice$.pipe((0, import_cjs$16.map)((deviceInfo) => ["video", deviceInfo]))).pipe((0, import_cjs$16.skipWhile)(() => !this.localStreamController.localStream)), async ([kind, deviceInfo]) => {
|
|
15930
|
+
logger$16.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {
|
|
15674
15931
|
kind,
|
|
15675
15932
|
deviceInfo
|
|
15676
15933
|
});
|
|
@@ -15687,7 +15944,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15687
15944
|
this._initialized$.next(true);
|
|
15688
15945
|
}
|
|
15689
15946
|
} catch (error) {
|
|
15690
|
-
logger$
|
|
15947
|
+
logger$16.error("[RTCPeerConnectionController] Initialization error:", error);
|
|
15691
15948
|
this._errors$.next(toError(error));
|
|
15692
15949
|
this.destroy();
|
|
15693
15950
|
}
|
|
@@ -15719,22 +15976,22 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15719
15976
|
}
|
|
15720
15977
|
async startNegotiation() {
|
|
15721
15978
|
if (this.isNegotiating) {
|
|
15722
|
-
logger$
|
|
15979
|
+
logger$16.debug("[RTCPeerConnectionController] Negotiation already in progress, skipping.");
|
|
15723
15980
|
return;
|
|
15724
15981
|
}
|
|
15725
15982
|
this.setupEventListeners();
|
|
15726
15983
|
if (this.type === "answer") {
|
|
15727
|
-
logger$
|
|
15984
|
+
logger$16.debug("[RTCPeerConnectionController] This is an answer type still, skipping offer creation.");
|
|
15728
15985
|
return;
|
|
15729
15986
|
}
|
|
15730
15987
|
this._isNegotiating$.next(true);
|
|
15731
|
-
logger$
|
|
15988
|
+
logger$16.debug("[RTCPeerConnectionController] Starting negotiation.");
|
|
15732
15989
|
try {
|
|
15733
15990
|
const { offerOptions } = this;
|
|
15734
|
-
logger$
|
|
15991
|
+
logger$16.debug("[RTCPeerConnectionController] Creating offer with options:", offerOptions);
|
|
15735
15992
|
await this.createOffer(offerOptions);
|
|
15736
15993
|
} catch (error) {
|
|
15737
|
-
logger$
|
|
15994
|
+
logger$16.error("[RTCPeerConnectionController] Error during negotiation:", error);
|
|
15738
15995
|
this._errors$.next(toError(error));
|
|
15739
15996
|
}
|
|
15740
15997
|
}
|
|
@@ -15750,14 +16007,14 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15750
16007
|
let readyToConnect = status !== "failed";
|
|
15751
16008
|
try {
|
|
15752
16009
|
if (status === "received" && sdp) {
|
|
15753
|
-
logger$
|
|
16010
|
+
logger$16.debug("[RTCPeerConnectionController] Received answer SDP:", sdp);
|
|
15754
16011
|
await this._setRemoteDescription({
|
|
15755
16012
|
type: "answer",
|
|
15756
16013
|
sdp
|
|
15757
16014
|
});
|
|
15758
16015
|
}
|
|
15759
16016
|
} catch (error) {
|
|
15760
|
-
logger$
|
|
16017
|
+
logger$16.error("[RTCPeerConnectionController] Error updating answer status:", error);
|
|
15761
16018
|
this._errors$.next(toError(error));
|
|
15762
16019
|
readyToConnect = false;
|
|
15763
16020
|
} finally {
|
|
@@ -15776,7 +16033,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15776
16033
|
await this.handleOfferReceived();
|
|
15777
16034
|
break;
|
|
15778
16035
|
case "failed":
|
|
15779
|
-
logger$
|
|
16036
|
+
logger$16.error("[RTCPeerConnectionController] Offer failed to be processed by remote.");
|
|
15780
16037
|
break;
|
|
15781
16038
|
case "sent":
|
|
15782
16039
|
default:
|
|
@@ -15808,7 +16065,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15808
16065
|
}
|
|
15809
16066
|
await this.setupLocalTracks();
|
|
15810
16067
|
const { answerOptions } = this;
|
|
15811
|
-
logger$
|
|
16068
|
+
logger$16.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
|
|
15812
16069
|
await this.createAnswer(answerOptions);
|
|
15813
16070
|
}
|
|
15814
16071
|
async handleOfferReceived() {
|
|
@@ -15816,7 +16073,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15816
16073
|
this._isNegotiating$.next(true);
|
|
15817
16074
|
await this._setRemoteDescription(this.sdpInit);
|
|
15818
16075
|
const { answerOptions } = this;
|
|
15819
|
-
logger$
|
|
16076
|
+
logger$16.debug("[RTCPeerConnectionController] Creating answer with options:", answerOptions);
|
|
15820
16077
|
await this.createAnswer(answerOptions);
|
|
15821
16078
|
}
|
|
15822
16079
|
readyToConnect() {
|
|
@@ -15824,7 +16081,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15824
16081
|
this.connectionTimer = setTimeout(() => {
|
|
15825
16082
|
this.removeConnectionTimer();
|
|
15826
16083
|
if (this.peerConnection?.connectionState !== "connected") {
|
|
15827
|
-
logger$
|
|
16084
|
+
logger$16.debug("[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.");
|
|
15828
16085
|
this.iceGatheringController.restartICEGatheringWithRelayOnly();
|
|
15829
16086
|
}
|
|
15830
16087
|
}, this.connectionTimeout);
|
|
@@ -15846,14 +16103,14 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15846
16103
|
const stereo = this.options.stereo ?? PreferencesContainer.instance.stereoAudio;
|
|
15847
16104
|
if (preferredAudioCodecs.length > 0 || preferredVideoCodecs.length > 0) {
|
|
15848
16105
|
result = setCodecPreferences(result, preferredAudioCodecs, preferredVideoCodecs);
|
|
15849
|
-
logger$
|
|
16106
|
+
logger$16.debug("[RTCPeerConnectionController] Applied codec preferences to SDP", {
|
|
15850
16107
|
preferredAudioCodecs,
|
|
15851
16108
|
preferredVideoCodecs
|
|
15852
16109
|
});
|
|
15853
16110
|
}
|
|
15854
16111
|
if (stereo) {
|
|
15855
16112
|
result = enableStereoOpus(result);
|
|
15856
|
-
logger$
|
|
16113
|
+
logger$16.debug("[RTCPeerConnectionController] Applied stereo Opus to SDP");
|
|
15857
16114
|
}
|
|
15858
16115
|
return Promise.resolve(result);
|
|
15859
16116
|
}
|
|
@@ -15887,9 +16144,6 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15887
16144
|
negotiationEnded() {
|
|
15888
16145
|
this._isNegotiating$.next(false);
|
|
15889
16146
|
}
|
|
15890
|
-
restarIce() {
|
|
15891
|
-
this.peerConnection?.restartIce();
|
|
15892
|
-
}
|
|
15893
16147
|
/**
|
|
15894
16148
|
* Trigger an ICE restart through the existing negotiation pipeline.
|
|
15895
16149
|
*
|
|
@@ -15912,24 +16166,27 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15912
16166
|
...this.peerConnection.getConfiguration(),
|
|
15913
16167
|
iceTransportPolicy: "relay"
|
|
15914
16168
|
});
|
|
15915
|
-
logger$
|
|
16169
|
+
logger$16.debug("[RTCPeerConnectionController] ICE transport policy set to relay-only");
|
|
15916
16170
|
} catch (error) {
|
|
15917
|
-
logger$
|
|
16171
|
+
logger$16.warn("[RTCPeerConnectionController] Failed to set relay-only policy:", error);
|
|
15918
16172
|
}
|
|
15919
16173
|
this.setupEventListeners();
|
|
15920
16174
|
this._isNegotiating$.next(true);
|
|
15921
|
-
logger$
|
|
16175
|
+
logger$16.debug(`[RTCPeerConnectionController] Triggering ICE restart${relayOnly ? " (relay-only)" : ""}.`);
|
|
15922
16176
|
try {
|
|
15923
16177
|
const offer = await this.peerConnection.createOffer({ iceRestart: true });
|
|
15924
16178
|
await this.setLocalDescription(offer);
|
|
15925
16179
|
} catch (error) {
|
|
15926
|
-
logger$
|
|
16180
|
+
logger$16.error("[RTCPeerConnectionController] ICE restart offer failed:", error);
|
|
15927
16181
|
this._errors$.next(toError(error));
|
|
15928
16182
|
this.negotiationEnded();
|
|
15929
16183
|
if (policyChanged) this.restoreIceTransportPolicy();
|
|
15930
16184
|
throw error;
|
|
15931
16185
|
}
|
|
15932
|
-
if (policyChanged) this.restoreIceTransportPolicy()
|
|
16186
|
+
if (policyChanged) (0, import_cjs$16.firstValueFrom)((0, import_cjs$16.race)(this._iceGatheringState$.pipe((0, import_cjs$16.filter)((state) => state === "complete"), (0, import_cjs$16.take)(1)), (0, import_cjs$16.timer)(ICE_GATHERING_COMPLETE_TIMEOUT_MS).pipe((0, import_cjs$16.map)(() => "timeout")))).then(() => this.restoreIceTransportPolicy()).catch((error) => {
|
|
16187
|
+
logger$16.warn("[RTCPeerConnectionController] Error waiting for ICE gathering to complete:", error);
|
|
16188
|
+
this.restoreIceTransportPolicy();
|
|
16189
|
+
});
|
|
15933
16190
|
}
|
|
15934
16191
|
restoreIceTransportPolicy() {
|
|
15935
16192
|
try {
|
|
@@ -15937,9 +16194,9 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15937
16194
|
...this.peerConnection.getConfiguration(),
|
|
15938
16195
|
iceTransportPolicy: this.options.relayOnly ? "relay" : "all"
|
|
15939
16196
|
});
|
|
15940
|
-
logger$
|
|
16197
|
+
logger$16.debug("[RTCPeerConnectionController] ICE transport policy restored");
|
|
15941
16198
|
} catch (error) {
|
|
15942
|
-
logger$
|
|
16199
|
+
logger$16.warn("[RTCPeerConnectionController] Failed to restore ICE transport policy:", error);
|
|
15943
16200
|
}
|
|
15944
16201
|
}
|
|
15945
16202
|
/**
|
|
@@ -15951,13 +16208,13 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15951
16208
|
await this.setupRemoteTracks();
|
|
15952
16209
|
}
|
|
15953
16210
|
async setupLocalTracks() {
|
|
15954
|
-
logger$
|
|
16211
|
+
logger$16.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
|
|
15955
16212
|
const localStream = this.localStream ?? await this.localStreamController.buildLocalStream();
|
|
15956
16213
|
if (this.transceiverController?.useAddStream ?? false) {
|
|
15957
|
-
logger$
|
|
16214
|
+
logger$16.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
|
|
15958
16215
|
this.peerConnection?.addStream(localStream);
|
|
15959
16216
|
if (!this.isNegotiating) {
|
|
15960
|
-
logger$
|
|
16217
|
+
logger$16.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
|
|
15961
16218
|
this.negotiationNeeded$.next();
|
|
15962
16219
|
}
|
|
15963
16220
|
return;
|
|
@@ -15973,7 +16230,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15973
16230
|
const transceivers = (kind === "audio" ? this.transceiverController?.audioTransceivers : this.transceiverController?.videoTransceivers) ?? [];
|
|
15974
16231
|
await this.transceiverController?.setupTransceiverSender(track, localStream, transceivers[index]);
|
|
15975
16232
|
} else {
|
|
15976
|
-
logger$
|
|
16233
|
+
logger$16.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
|
|
15977
16234
|
this.peerConnection?.addTrack(track, localStream);
|
|
15978
16235
|
}
|
|
15979
16236
|
}
|
|
@@ -15990,7 +16247,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15990
16247
|
async setupRemoteTracks() {
|
|
15991
16248
|
if (!this.peerConnection) throw new DependencyError("RTCPeerConnection is not initialized");
|
|
15992
16249
|
this.peerConnection.ontrack = (event) => {
|
|
15993
|
-
logger$
|
|
16250
|
+
logger$16.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
|
|
15994
16251
|
if (event.streams[0]) this._remoteStream$.next(event.streams[0]);
|
|
15995
16252
|
else {
|
|
15996
16253
|
const existingTracks = this._remoteStream$.value?.getTracks() ?? [];
|
|
@@ -16002,6 +16259,45 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16002
16259
|
}
|
|
16003
16260
|
async restoreTrackSender(kind) {
|
|
16004
16261
|
await this.transceiverController?.restoreTrackSender(kind);
|
|
16262
|
+
if (kind !== "video" && this._localAudioPipeline) await this.applyLocalAudioPipelineToSender();
|
|
16263
|
+
}
|
|
16264
|
+
/**
|
|
16265
|
+
* Return the lazily-created {@link LocalAudioPipeline}, constructing it on
|
|
16266
|
+
* first access. On creation the current audio sender's track is routed
|
|
16267
|
+
* through the pipeline (input → gain → analyser → destination) and the
|
|
16268
|
+
* sender is switched to emit the processed track. Returns `null` when no
|
|
16269
|
+
* audio sender exists yet (pre-negotiation).
|
|
16270
|
+
*/
|
|
16271
|
+
ensureLocalAudioPipeline() {
|
|
16272
|
+
if (this._localAudioPipeline) return this._localAudioPipeline;
|
|
16273
|
+
if (!this.peerConnection) return null;
|
|
16274
|
+
try {
|
|
16275
|
+
this._localAudioPipeline = new LocalAudioPipeline();
|
|
16276
|
+
} catch (error) {
|
|
16277
|
+
logger$16.warn("[RTCPeerConnectionController] Failed to create LocalAudioPipeline:", error);
|
|
16278
|
+
return null;
|
|
16279
|
+
}
|
|
16280
|
+
this.subscribeTo(this.localStreamController.localAudioTracks$, () => {
|
|
16281
|
+
this.applyLocalAudioPipelineToSender();
|
|
16282
|
+
});
|
|
16283
|
+
this.applyLocalAudioPipelineToSender();
|
|
16284
|
+
return this._localAudioPipeline;
|
|
16285
|
+
}
|
|
16286
|
+
/** The active LocalAudioPipeline, or null if it hasn't been created yet. */
|
|
16287
|
+
get localAudioPipeline() {
|
|
16288
|
+
return this._localAudioPipeline;
|
|
16289
|
+
}
|
|
16290
|
+
async applyLocalAudioPipelineToSender() {
|
|
16291
|
+
if (!this._localAudioPipeline || !this.peerConnection) return;
|
|
16292
|
+
const raw = this.localStreamController.localAudioTracks.at(0);
|
|
16293
|
+
this._localAudioPipeline.setInputTrack(raw ?? null);
|
|
16294
|
+
const sender = (this.transceiverController?.audioTransceivers.at(0))?.sender ?? this.peerConnection.getSenders().find((s) => s.track?.kind === "audio");
|
|
16295
|
+
if (!sender || !raw) return;
|
|
16296
|
+
try {
|
|
16297
|
+
await sender.replaceTrack(this._localAudioPipeline.outputTrack);
|
|
16298
|
+
} catch (error) {
|
|
16299
|
+
logger$16.warn("[RTCPeerConnectionController] Failed to route audio sender through pipeline:", error);
|
|
16300
|
+
}
|
|
16005
16301
|
}
|
|
16006
16302
|
/**
|
|
16007
16303
|
* Add a local media track to the peer connection.
|
|
@@ -16016,9 +16312,9 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16016
16312
|
try {
|
|
16017
16313
|
const localStream = this.localStreamController.addTrack(track);
|
|
16018
16314
|
this.peerConnection.addTrack(track, localStream);
|
|
16019
|
-
logger$
|
|
16315
|
+
logger$16.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);
|
|
16020
16316
|
} catch (error) {
|
|
16021
|
-
logger$
|
|
16317
|
+
logger$16.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);
|
|
16022
16318
|
this._errors$.next(toError(error));
|
|
16023
16319
|
throw error;
|
|
16024
16320
|
}
|
|
@@ -16035,15 +16331,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16035
16331
|
}
|
|
16036
16332
|
const sender = this.peerConnection.getSenders().find((sender$1) => sender$1.track?.id === trackId);
|
|
16037
16333
|
if (!sender) {
|
|
16038
|
-
logger$
|
|
16334
|
+
logger$16.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);
|
|
16039
16335
|
return;
|
|
16040
16336
|
}
|
|
16041
16337
|
try {
|
|
16042
16338
|
this.peerConnection.removeTrack(sender);
|
|
16043
16339
|
this.localStreamController.removeTrack(trackId);
|
|
16044
|
-
logger$
|
|
16340
|
+
logger$16.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);
|
|
16045
16341
|
} catch (error) {
|
|
16046
|
-
logger$
|
|
16342
|
+
logger$16.error(`[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`, error);
|
|
16047
16343
|
this._errors$.next(toError(error));
|
|
16048
16344
|
throw error;
|
|
16049
16345
|
}
|
|
@@ -16070,7 +16366,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16070
16366
|
async replaceAudioTrackWithConstraints(constraints) {
|
|
16071
16367
|
const senders = this.peerConnection?.getSenders().filter((s) => s.track?.kind === "audio" && s.track.readyState === "live");
|
|
16072
16368
|
if (!senders || senders.length === 0) {
|
|
16073
|
-
logger$
|
|
16369
|
+
logger$16.warn("[RTCPeerConnectionController] No live audio sender to replace");
|
|
16074
16370
|
return;
|
|
16075
16371
|
}
|
|
16076
16372
|
for (const sender of senders) {
|
|
@@ -16088,7 +16384,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16088
16384
|
const newTrack = (await this.getUserMedia({ audio: mergedConstraints })).getAudioTracks()[0];
|
|
16089
16385
|
await sender.replaceTrack(newTrack);
|
|
16090
16386
|
this.localStreamController.addTrack(newTrack);
|
|
16091
|
-
logger$
|
|
16387
|
+
logger$16.debug(`[RTCPeerConnectionController] Audio track replaced for server-pushed params. New track: ${newTrack.id}`);
|
|
16092
16388
|
}
|
|
16093
16389
|
}
|
|
16094
16390
|
/**
|
|
@@ -16096,9 +16392,11 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16096
16392
|
* Completes all observables to prevent memory leaks.
|
|
16097
16393
|
*/
|
|
16098
16394
|
destroy() {
|
|
16099
|
-
logger$
|
|
16395
|
+
logger$16.debug(`[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`);
|
|
16100
16396
|
this.removeConnectionTimer();
|
|
16101
16397
|
this._iceGatheringController?.destroy();
|
|
16398
|
+
this._localAudioPipeline?.destroy();
|
|
16399
|
+
this._localAudioPipeline = null;
|
|
16102
16400
|
this.localStreamController.destroy();
|
|
16103
16401
|
this.transceiverController?.destroy();
|
|
16104
16402
|
if (this.peerConnection) {
|
|
@@ -16120,7 +16418,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16120
16418
|
}
|
|
16121
16419
|
stopRemoteTracks() {
|
|
16122
16420
|
this._remoteStream$.value?.getTracks().forEach((track) => {
|
|
16123
|
-
logger$
|
|
16421
|
+
logger$16.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);
|
|
16124
16422
|
track.stop();
|
|
16125
16423
|
});
|
|
16126
16424
|
}
|
|
@@ -16137,7 +16435,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16137
16435
|
...params,
|
|
16138
16436
|
sdp: finalRemote
|
|
16139
16437
|
};
|
|
16140
|
-
logger$
|
|
16438
|
+
logger$16.debug("[RTCPeerConnectionController] Setting remote description:", answer);
|
|
16141
16439
|
return this.peerConnection.setRemoteDescription(answer);
|
|
16142
16440
|
}
|
|
16143
16441
|
};
|
|
@@ -16175,8 +16473,25 @@ function isVertoPingInnerParams(value) {
|
|
|
16175
16473
|
|
|
16176
16474
|
//#endregion
|
|
16177
16475
|
//#region src/managers/VertoManager.ts
|
|
16178
|
-
var import_cjs$
|
|
16179
|
-
const logger$
|
|
16476
|
+
var import_cjs$15 = require_cjs();
|
|
16477
|
+
const logger$15 = getLogger();
|
|
16478
|
+
/**
|
|
16479
|
+
* Decide what value goes on the `node_id` field of a `webrtc.verto` envelope.
|
|
16480
|
+
*
|
|
16481
|
+
* - **Reattach invite:** must carry the persisted nodeId so the server routes
|
|
16482
|
+
* the new connection to the FreeSWITCH instance that holds the existing call.
|
|
16483
|
+
* - **Fresh invite, caller-supplied `CallOptions.nodeId`:** carry the explicit
|
|
16484
|
+
* value as a steering hint (dev/staging traffic pinning). Server may honour
|
|
16485
|
+
* or ignore for placement reasons.
|
|
16486
|
+
* - **Fresh invite, no caller nodeId:** strip to `''` = "server picks".
|
|
16487
|
+
* - **Non-invite frames** (verto.modify, verto.bye, etc.): always carry the
|
|
16488
|
+
* current `_nodeId$.value` so the frame targets the node hosting the call.
|
|
16489
|
+
*
|
|
16490
|
+
* Pure function — exported for unit testing.
|
|
16491
|
+
*/
|
|
16492
|
+
function resolveInviteNodeId(args) {
|
|
16493
|
+
return args.isInvite && !args.reattach && !args.explicitNodeId ? "" : args.currentNodeId ?? "";
|
|
16494
|
+
}
|
|
16180
16495
|
var VertoManager = class extends Destroyable {
|
|
16181
16496
|
constructor(callSession) {
|
|
16182
16497
|
super();
|
|
@@ -16215,7 +16530,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16215
16530
|
try {
|
|
16216
16531
|
await this.executeVerto(vertoModifyMessage);
|
|
16217
16532
|
} catch (error) {
|
|
16218
|
-
logger$
|
|
16533
|
+
logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto hold:", error);
|
|
16219
16534
|
throw error;
|
|
16220
16535
|
}
|
|
16221
16536
|
}
|
|
@@ -16228,7 +16543,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16228
16543
|
try {
|
|
16229
16544
|
await this.executeVerto(vertoModifyMessage);
|
|
16230
16545
|
} catch (error) {
|
|
16231
|
-
logger$
|
|
16546
|
+
logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto unhold:", error);
|
|
16232
16547
|
throw error;
|
|
16233
16548
|
}
|
|
16234
16549
|
}
|
|
@@ -16268,7 +16583,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16268
16583
|
return rtcPeerConnection;
|
|
16269
16584
|
}
|
|
16270
16585
|
get signalingStatus$() {
|
|
16271
|
-
return this.cachedObservable("signalingStatus$", () => (0, import_cjs$
|
|
16586
|
+
return this.cachedObservable("signalingStatus$", () => (0, import_cjs$15.merge)(this._signalingStatus$.asObservable(), this.mainPeerConnection.connectionState$.pipe((0, import_cjs$15.filter)((connectionState) => [
|
|
16272
16587
|
"connected",
|
|
16273
16588
|
"disconnected",
|
|
16274
16589
|
"failed"
|
|
@@ -16281,7 +16596,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16281
16596
|
if (event.member_id) this.setSelfIdIfNull(event.member_id);
|
|
16282
16597
|
});
|
|
16283
16598
|
this.subscribeTo(this.vertoMedia$, (event) => {
|
|
16284
|
-
logger$
|
|
16599
|
+
logger$15.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
|
|
16285
16600
|
this._signalingStatus$.next("ringing");
|
|
16286
16601
|
const { sdp, callID } = event;
|
|
16287
16602
|
this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
|
|
@@ -16290,7 +16605,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16290
16605
|
});
|
|
16291
16606
|
});
|
|
16292
16607
|
this.subscribeTo(this.vertoAnswer$, (event) => {
|
|
16293
|
-
logger$
|
|
16608
|
+
logger$15.debug("[WebRTCManager] Received Verto answer event:", event);
|
|
16294
16609
|
this._signalingStatus$.next("connecting");
|
|
16295
16610
|
const { sdp, callID } = event;
|
|
16296
16611
|
this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
|
|
@@ -16299,7 +16614,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16299
16614
|
});
|
|
16300
16615
|
});
|
|
16301
16616
|
this.subscribeTo(this.vertoMediaParams$, (event) => {
|
|
16302
|
-
logger$
|
|
16617
|
+
logger$15.debug("[WebRTCManager] Received Verto mediaParams event:", event);
|
|
16303
16618
|
const { mediaParams, callID } = event;
|
|
16304
16619
|
const rtcPeerConnController = this._rtcPeerConnectionsMap.get(callID);
|
|
16305
16620
|
const { audio, video } = mediaParams;
|
|
@@ -16313,7 +16628,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16313
16628
|
timestamp: Date.now()
|
|
16314
16629
|
});
|
|
16315
16630
|
} catch (error) {
|
|
16316
|
-
logger$
|
|
16631
|
+
logger$15.warn("[WebRTCManager] Error applying server-pushed media params:", error);
|
|
16317
16632
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16318
16633
|
}
|
|
16319
16634
|
})();
|
|
@@ -16335,13 +16650,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16335
16650
|
*/
|
|
16336
16651
|
setNodeIdIfNull(nodeId) {
|
|
16337
16652
|
if (!this._nodeId$.value && nodeId) {
|
|
16338
|
-
logger$
|
|
16653
|
+
logger$15.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
|
|
16339
16654
|
this._nodeId$.next(nodeId);
|
|
16340
16655
|
}
|
|
16341
16656
|
}
|
|
16342
16657
|
setSelfIdIfNull(selfId) {
|
|
16343
16658
|
if (!this._selfId$.value && selfId) {
|
|
16344
|
-
logger$
|
|
16659
|
+
logger$15.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
|
|
16345
16660
|
this._selfId$.next(selfId);
|
|
16346
16661
|
}
|
|
16347
16662
|
}
|
|
@@ -16350,7 +16665,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16350
16665
|
const vertoPongMessage = VertoPong({ ...vertoPing });
|
|
16351
16666
|
await this.executeVerto(vertoPongMessage);
|
|
16352
16667
|
} catch (error) {
|
|
16353
|
-
logger$
|
|
16668
|
+
logger$15.warn("[WebRTCManager] Call might disconnect, error sending Verto pong:", error);
|
|
16354
16669
|
this.onError?.(new VertoPongError(error));
|
|
16355
16670
|
}
|
|
16356
16671
|
}
|
|
@@ -16360,7 +16675,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16360
16675
|
if (audio) await this.mainPeerConnection.updateSendersConstraints("audio", audio);
|
|
16361
16676
|
if (video) await this.mainPeerConnection.updateSendersConstraints("video", video);
|
|
16362
16677
|
} catch (error) {
|
|
16363
|
-
logger$
|
|
16678
|
+
logger$15.warn("[WebRTCManager] Error updating media constraints:", error);
|
|
16364
16679
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16365
16680
|
throw error;
|
|
16366
16681
|
}
|
|
@@ -16390,20 +16705,20 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16390
16705
|
try {
|
|
16391
16706
|
const pc = this.mainPeerConnection.peerConnection;
|
|
16392
16707
|
if (!pc) {
|
|
16393
|
-
logger$
|
|
16708
|
+
logger$15.warn("[WebRTCManager] No peer connection for keyframe request");
|
|
16394
16709
|
return;
|
|
16395
16710
|
}
|
|
16396
16711
|
const videoReceiver = pc.getReceivers().find((r) => r.track.kind === "video");
|
|
16397
16712
|
if (!videoReceiver) {
|
|
16398
|
-
logger$
|
|
16713
|
+
logger$15.warn("[WebRTCManager] No video receiver for keyframe request");
|
|
16399
16714
|
return;
|
|
16400
16715
|
}
|
|
16401
16716
|
if (typeof videoReceiver.requestKeyFrame === "function") {
|
|
16402
16717
|
videoReceiver.requestKeyFrame();
|
|
16403
|
-
logger$
|
|
16404
|
-
} else logger$
|
|
16718
|
+
logger$15.debug("[WebRTCManager] Keyframe requested via RTCRtpReceiver.requestKeyFrame()");
|
|
16719
|
+
} else logger$15.debug("[WebRTCManager] requestKeyFrame() not supported, skipping");
|
|
16405
16720
|
} catch (error) {
|
|
16406
|
-
logger$
|
|
16721
|
+
logger$15.warn("[WebRTCManager] Keyframe request failed (non-fatal):", error);
|
|
16407
16722
|
}
|
|
16408
16723
|
}
|
|
16409
16724
|
/**
|
|
@@ -16421,13 +16736,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16421
16736
|
try {
|
|
16422
16737
|
const controller = this.mainPeerConnection;
|
|
16423
16738
|
if (!controller.peerConnection) {
|
|
16424
|
-
logger$
|
|
16739
|
+
logger$15.warn("[WebRTCManager] No peer connection for ICE restart");
|
|
16425
16740
|
return;
|
|
16426
16741
|
}
|
|
16427
16742
|
await controller.triggerIceRestart(relayOnly);
|
|
16428
|
-
logger$
|
|
16743
|
+
logger$15.info(`[WebRTCManager] ICE restart initiated${relayOnly ? " (relay-only)" : ""}`);
|
|
16429
16744
|
} catch (error) {
|
|
16430
|
-
logger$
|
|
16745
|
+
logger$15.error("[WebRTCManager] ICE restart failed:", error);
|
|
16431
16746
|
throw error;
|
|
16432
16747
|
}
|
|
16433
16748
|
}
|
|
@@ -16445,13 +16760,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16445
16760
|
const entries = Array.from(this._rtcPeerConnectionsMap.entries());
|
|
16446
16761
|
for (const [id, controller] of entries) try {
|
|
16447
16762
|
if (!controller.peerConnection) {
|
|
16448
|
-
logger$
|
|
16763
|
+
logger$15.debug(`[WebRTCManager] No peer connection for leg ${id}, skipping ICE restart`);
|
|
16449
16764
|
continue;
|
|
16450
16765
|
}
|
|
16451
16766
|
await controller.triggerIceRestart(relayOnly);
|
|
16452
|
-
logger$
|
|
16767
|
+
logger$15.info(`[WebRTCManager] ICE restart initiated for leg ${id}${relayOnly ? " (relay-only)" : ""}`);
|
|
16453
16768
|
} catch (error) {
|
|
16454
|
-
logger$
|
|
16769
|
+
logger$15.warn(`[WebRTCManager] ICE restart failed for leg ${id}:`, error);
|
|
16455
16770
|
}
|
|
16456
16771
|
}
|
|
16457
16772
|
/**
|
|
@@ -16463,7 +16778,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16463
16778
|
requestKeyframeAll() {
|
|
16464
16779
|
for (const [id, controller] of this._rtcPeerConnectionsMap) {
|
|
16465
16780
|
if (controller.isScreenShare) {
|
|
16466
|
-
logger$
|
|
16781
|
+
logger$15.debug(`[WebRTCManager] Skipping keyframe for send-only screen share leg ${id}`);
|
|
16467
16782
|
continue;
|
|
16468
16783
|
}
|
|
16469
16784
|
try {
|
|
@@ -16473,33 +16788,33 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16473
16788
|
if (!videoReceiver) continue;
|
|
16474
16789
|
if (typeof videoReceiver.requestKeyFrame === "function") {
|
|
16475
16790
|
videoReceiver.requestKeyFrame();
|
|
16476
|
-
logger$
|
|
16791
|
+
logger$15.debug(`[WebRTCManager] Keyframe requested for leg ${id}`);
|
|
16477
16792
|
}
|
|
16478
16793
|
} catch (error) {
|
|
16479
|
-
logger$
|
|
16794
|
+
logger$15.warn(`[WebRTCManager] Keyframe request failed for leg ${id} (non-fatal):`, error);
|
|
16480
16795
|
}
|
|
16481
16796
|
}
|
|
16482
16797
|
}
|
|
16483
16798
|
get callJoinedEvent$() {
|
|
16484
|
-
return this.webRtcCallSession.callEvent$.pipe((0, import_cjs$
|
|
16799
|
+
return this.webRtcCallSession.callEvent$.pipe((0, import_cjs$15.filter)(isCallJoinedPayload), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16485
16800
|
}
|
|
16486
16801
|
get vertoMedia$() {
|
|
16487
|
-
return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$
|
|
16802
|
+
return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16488
16803
|
}
|
|
16489
16804
|
get vertoAnswer$() {
|
|
16490
|
-
return this.cachedObservable("vertoAnswer$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAnswerInnerParams, "params"), (0, import_cjs$
|
|
16805
|
+
return this.cachedObservable("vertoAnswer$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAnswerInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16491
16806
|
}
|
|
16492
16807
|
get vertoMediaParams$() {
|
|
16493
|
-
return this.cachedObservable("vertoMediaParams$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaParamsInnerParams, "params"), (0, import_cjs$
|
|
16808
|
+
return this.cachedObservable("vertoMediaParams$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaParamsInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16494
16809
|
}
|
|
16495
16810
|
get vertoBye$() {
|
|
16496
|
-
return this.cachedObservable("vertoBye$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoByeMessage, "params"), (0, import_cjs$
|
|
16811
|
+
return this.cachedObservable("vertoBye$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoByeMessage, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16497
16812
|
}
|
|
16498
16813
|
get vertoAttach$() {
|
|
16499
|
-
return this.cachedObservable("vertoAttach$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAttachMessage, "params"), (0, import_cjs$
|
|
16814
|
+
return this.cachedObservable("vertoAttach$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAttachMessage, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16500
16815
|
}
|
|
16501
16816
|
get vertoPing$() {
|
|
16502
|
-
return this.cachedObservable("vertoPing$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoPingInnerParams, "params"), (0, import_cjs$
|
|
16817
|
+
return this.cachedObservable("vertoPing$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoPingInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16503
16818
|
}
|
|
16504
16819
|
async executeVerto(message, optionals = {}) {
|
|
16505
16820
|
const webrtcVertoMessage = WebrtcVerto({
|
|
@@ -16537,7 +16852,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16537
16852
|
default:
|
|
16538
16853
|
}
|
|
16539
16854
|
} catch (error) {
|
|
16540
|
-
logger$
|
|
16855
|
+
logger$15.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
|
|
16541
16856
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16542
16857
|
if (vertoMethod === "verto.modify") this.onModifyFailed?.();
|
|
16543
16858
|
}
|
|
@@ -16552,7 +16867,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16552
16867
|
sdp
|
|
16553
16868
|
});
|
|
16554
16869
|
} catch (error) {
|
|
16555
|
-
logger$
|
|
16870
|
+
logger$15.warn("[WebRTCManager] Error processing modify response:", error);
|
|
16556
16871
|
const modifyError = error instanceof Error ? error : new Error(String(error), { cause: error });
|
|
16557
16872
|
this.onError?.(modifyError);
|
|
16558
16873
|
}
|
|
@@ -16564,7 +16879,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16564
16879
|
this._nodeId$.next(getValueFrom(response, "result.node_id") ?? null);
|
|
16565
16880
|
const memberId = getValueFrom(response, "result.result.result.memberID") ?? null;
|
|
16566
16881
|
const callId = getValueFrom(response, "result.result.result.callID") ?? null;
|
|
16567
|
-
logger$
|
|
16882
|
+
logger$15.debug("[WebRTCManager] Verto invite response:", {
|
|
16568
16883
|
callId,
|
|
16569
16884
|
memberId,
|
|
16570
16885
|
response
|
|
@@ -16574,14 +16889,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16574
16889
|
if (callId) {
|
|
16575
16890
|
this.webRtcCallSession.addCallId(callId);
|
|
16576
16891
|
this.attachManager.attach(this.buildAttachableCall(callId));
|
|
16577
|
-
} else logger$
|
|
16892
|
+
} else logger$15.warn("[WebRTCManager] Cannot attach call, missing callId:", {
|
|
16578
16893
|
nodeId: this.nodeId,
|
|
16579
16894
|
callId
|
|
16580
16895
|
});
|
|
16581
|
-
logger$
|
|
16582
|
-
logger$
|
|
16896
|
+
logger$15.info("[WebRTCManager] Verto invite successful");
|
|
16897
|
+
logger$15.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
|
|
16583
16898
|
} else {
|
|
16584
|
-
logger$
|
|
16899
|
+
logger$15.error("[WebRTCManager] Verto invite failed:", response);
|
|
16585
16900
|
const inviteError = response.error ? new JSONRPCError(response.error.code, response.error.message, response.error.data) : /* @__PURE__ */ new Error("Verto invite failed: unexpected response");
|
|
16586
16901
|
this.onError?.(inviteError);
|
|
16587
16902
|
}
|
|
@@ -16626,17 +16941,17 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16626
16941
|
if (options.initOffer) this.handleInboundAnswer(rtcPeerConnController);
|
|
16627
16942
|
}
|
|
16628
16943
|
async handleInboundAnswer(rtcPeerConnController) {
|
|
16629
|
-
logger$
|
|
16630
|
-
const vertoByeOrAccepted = await (0, import_cjs$
|
|
16944
|
+
logger$15.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
|
|
16945
|
+
const vertoByeOrAccepted = await (0, import_cjs$15.firstValueFrom)((0, import_cjs$15.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, import_cjs$15.takeUntil)(this.destroyed$))).catch(() => null);
|
|
16631
16946
|
if (vertoByeOrAccepted === null) {
|
|
16632
|
-
logger$
|
|
16947
|
+
logger$15.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
|
|
16633
16948
|
return;
|
|
16634
16949
|
}
|
|
16635
16950
|
if (isVertoByeMessage(vertoByeOrAccepted)) {
|
|
16636
|
-
logger$
|
|
16951
|
+
logger$15.info("[WebRTCManager] Inbound call ended by remote before answer.");
|
|
16637
16952
|
this.callSession?.destroy();
|
|
16638
16953
|
} else if (!vertoByeOrAccepted) {
|
|
16639
|
-
logger$
|
|
16954
|
+
logger$15.info("[WebRTCManager] Inbound call rejected by user.");
|
|
16640
16955
|
try {
|
|
16641
16956
|
await this.bye("USER_BUSY");
|
|
16642
16957
|
} finally {
|
|
@@ -16644,19 +16959,19 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16644
16959
|
this.callSession?.destroy();
|
|
16645
16960
|
}
|
|
16646
16961
|
} else {
|
|
16647
|
-
logger$
|
|
16962
|
+
logger$15.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
|
|
16648
16963
|
const answerOptions = this.webRtcCallSession.answerMediaOptions;
|
|
16649
16964
|
try {
|
|
16650
16965
|
await rtcPeerConnController.acceptInbound(answerOptions);
|
|
16651
16966
|
} catch (error) {
|
|
16652
|
-
logger$
|
|
16967
|
+
logger$15.error("[WebRTCManager] Error creating inbound answer:", error);
|
|
16653
16968
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16654
16969
|
}
|
|
16655
16970
|
}
|
|
16656
16971
|
}
|
|
16657
16972
|
setupVertoAttachHandler() {
|
|
16658
16973
|
this.subscribeTo(this.vertoAttach$, async (vertoAttach) => {
|
|
16659
|
-
logger$
|
|
16974
|
+
logger$15.debug("[WebRTCManager] Received Verto attach event for existing call:", vertoAttach);
|
|
16660
16975
|
const { callID } = vertoAttach;
|
|
16661
16976
|
await this.attachManager.attach({
|
|
16662
16977
|
nodeId: this.nodeId ?? void 0,
|
|
@@ -16670,12 +16985,12 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16670
16985
|
});
|
|
16671
16986
|
}
|
|
16672
16987
|
initObservables(rtcPeerConnController) {
|
|
16673
|
-
this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, import_cjs$
|
|
16674
|
-
this.localStream$ = rtcPeerConnController.localStream$.pipe(filterNull(), (0, import_cjs$
|
|
16675
|
-
this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(filterNull(), (0, import_cjs$
|
|
16988
|
+
this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, import_cjs$15.filter)((state) => state === "connected"), (0, import_cjs$15.map)(() => rtcPeerConnController.mediaDirections), (0, import_cjs$15.startWith)(rtcPeerConnController.mediaDirections), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16989
|
+
this.localStream$ = rtcPeerConnController.localStream$.pipe(filterNull(), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16990
|
+
this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(filterNull(), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16676
16991
|
}
|
|
16677
16992
|
setupLocalDescriptionHandler(rtcPeerConnController) {
|
|
16678
|
-
this.subscribeTo(rtcPeerConnController.localDescription$.pipe((0, import_cjs$
|
|
16993
|
+
this.subscribeTo(rtcPeerConnController.localDescription$.pipe((0, import_cjs$15.filter)((description) => description !== null), (0, import_cjs$15.takeUntil)(this.destroyed$)), (description) => {
|
|
16679
16994
|
const { type, sdp } = description;
|
|
16680
16995
|
const dialogParams = this.dialogParams(rtcPeerConnController);
|
|
16681
16996
|
const initial = !rtcPeerConnController.firstSDPExchangeCompleted;
|
|
@@ -16716,26 +17031,29 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16716
17031
|
else if (rtcPeerConnController.isAdditionalDevice) subscribe.push(...PreferencesContainer.instance.inviteSubscribeAdditionalDevice);
|
|
16717
17032
|
else if (rtcPeerConnController.isScreenShare) subscribe.push(...PreferencesContainer.instance.inviteSubscribeScreenshare);
|
|
16718
17033
|
}
|
|
16719
|
-
const isInvite = isVertoInviteMessage(vertoMessage);
|
|
16720
|
-
const isReattach = isInvite && this.webRtcCallSession.options.reattach;
|
|
16721
17034
|
return {
|
|
16722
17035
|
callID: rtcPeerConnController.id,
|
|
16723
|
-
node_id:
|
|
17036
|
+
node_id: resolveInviteNodeId({
|
|
17037
|
+
isInvite: isVertoInviteMessage(vertoMessage),
|
|
17038
|
+
reattach: this.webRtcCallSession.options.reattach === true,
|
|
17039
|
+
explicitNodeId: this.webRtcCallSession.options.nodeId,
|
|
17040
|
+
currentNodeId: this._nodeId$.value
|
|
17041
|
+
}),
|
|
16724
17042
|
subscribe
|
|
16725
17043
|
};
|
|
16726
17044
|
}
|
|
16727
17045
|
async sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnectionController) {
|
|
16728
|
-
logger$
|
|
16729
|
-
const vertoByeOrAccepted = await (0, import_cjs$
|
|
17046
|
+
logger$15.debug("[WebRTCManager] Waiting for call to be accepted or ended before sending answer");
|
|
17047
|
+
const vertoByeOrAccepted = await (0, import_cjs$15.firstValueFrom)((0, import_cjs$15.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, import_cjs$15.takeUntil)(this.destroyed$))).catch(() => null);
|
|
16730
17048
|
if (vertoByeOrAccepted === null) {
|
|
16731
|
-
logger$
|
|
17049
|
+
logger$15.debug("[WebRTCManager] Destroyed while waiting for call acceptance");
|
|
16732
17050
|
return;
|
|
16733
17051
|
}
|
|
16734
17052
|
if (isVertoByeMessage(vertoByeOrAccepted)) {
|
|
16735
|
-
logger$
|
|
17053
|
+
logger$15.info("[WebRTCManager] Call ended before answer was sent.");
|
|
16736
17054
|
this.callSession?.destroy();
|
|
16737
17055
|
} else if (!vertoByeOrAccepted) {
|
|
16738
|
-
logger$
|
|
17056
|
+
logger$15.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
|
|
16739
17057
|
try {
|
|
16740
17058
|
await this.bye("USER_BUSY");
|
|
16741
17059
|
} finally {
|
|
@@ -16743,14 +17061,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16743
17061
|
this.callSession?.destroy();
|
|
16744
17062
|
}
|
|
16745
17063
|
} else {
|
|
16746
|
-
logger$
|
|
17064
|
+
logger$15.debug("[WebRTCManager] Call accepted, sending answer");
|
|
16747
17065
|
try {
|
|
16748
17066
|
this._signalingStatus$.next("connecting");
|
|
16749
17067
|
await this.sendLocalDescription(vertoMessageRequest, rtcPeerConnectionController);
|
|
16750
17068
|
await rtcPeerConnectionController.updateAnswerStatus({ status: "sent" });
|
|
16751
17069
|
await this.attachManager.attach(this.buildAttachableCall());
|
|
16752
17070
|
} catch (error) {
|
|
16753
|
-
logger$
|
|
17071
|
+
logger$15.error("[WebRTCManager] Error sending Verto answer:", error);
|
|
16754
17072
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16755
17073
|
await rtcPeerConnectionController.updateAnswerStatus({ status: "failed" });
|
|
16756
17074
|
}
|
|
@@ -16791,6 +17109,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16791
17109
|
async unmuteMainVideoInputDevice() {
|
|
16792
17110
|
return this.mainPeerConnection.restoreTrackSender("video");
|
|
16793
17111
|
}
|
|
17112
|
+
/** Get or lazily create the local audio pipeline for the main peer connection. */
|
|
17113
|
+
ensureLocalAudioPipeline() {
|
|
17114
|
+
return this.mainPeerConnection.ensureLocalAudioPipeline();
|
|
17115
|
+
}
|
|
17116
|
+
/** The currently-active local audio pipeline, or null if it hasn't been created. */
|
|
17117
|
+
get localAudioPipeline() {
|
|
17118
|
+
return this.mainPeerConnection.localAudioPipeline;
|
|
17119
|
+
}
|
|
16794
17120
|
async addInputDevice(options = {
|
|
16795
17121
|
audio: false,
|
|
16796
17122
|
video: true
|
|
@@ -16839,12 +17165,12 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16839
17165
|
this.subscribeTo(rtcPeerConnController.errors$, (error) => {
|
|
16840
17166
|
this.onError?.(error);
|
|
16841
17167
|
});
|
|
16842
|
-
await (0, import_cjs$
|
|
17168
|
+
await (0, import_cjs$15.firstValueFrom)(rtcPeerConnController.connectionState$.pipe((0, import_cjs$15.filter)((state) => state === "connected"), (0, import_cjs$15.take)(1), (0, import_cjs$15.timeout)(this._screenShareTimeoutMs), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16843
17169
|
this._screenShareStatus$.next("started");
|
|
16844
|
-
logger$
|
|
17170
|
+
logger$15.info("[WebRTCManager] Screen share started successfully.");
|
|
16845
17171
|
return rtcPeerConnController.id;
|
|
16846
17172
|
} catch (error) {
|
|
16847
|
-
logger$
|
|
17173
|
+
logger$15.warn("[WebRTCManager] Error initializing additional peer connection:", error);
|
|
16848
17174
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16849
17175
|
if (rtcPeerConnController) rtcPeerConnController.destroy();
|
|
16850
17176
|
this._screenShareStatus$.next("none");
|
|
@@ -16863,9 +17189,9 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16863
17189
|
if (removeTrack) return this.mainPeerConnection.stopTrackSender(removeTrack, { updateTransceiverDirection: true });
|
|
16864
17190
|
}
|
|
16865
17191
|
async removeScreenMedia() {
|
|
16866
|
-
if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$
|
|
17192
|
+
if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$15.warn("[WebRTCManager] No active screen share to stop.");
|
|
16867
17193
|
if (!this._screenShareId) {
|
|
16868
|
-
logger$
|
|
17194
|
+
logger$15.debug("[WebRTCManager] No screen share peer connection found.");
|
|
16869
17195
|
return;
|
|
16870
17196
|
}
|
|
16871
17197
|
this._screenShareStatus$.next("stopping");
|
|
@@ -16894,7 +17220,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16894
17220
|
dialogParams: this.dialogParams(rtcPeerConnController)
|
|
16895
17221
|
}));
|
|
16896
17222
|
} catch (error) {
|
|
16897
|
-
logger$
|
|
17223
|
+
logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto bye:", error);
|
|
16898
17224
|
throw error;
|
|
16899
17225
|
}
|
|
16900
17226
|
}
|
|
@@ -16912,7 +17238,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16912
17238
|
try {
|
|
16913
17239
|
await this.executeVerto(vertoInfoMessage);
|
|
16914
17240
|
} catch (error) {
|
|
16915
|
-
logger$
|
|
17241
|
+
logger$15.warn("[WebRTCManager] Error sending DTMF digits:", error);
|
|
16916
17242
|
throw error;
|
|
16917
17243
|
}
|
|
16918
17244
|
}
|
|
@@ -16923,10 +17249,10 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16923
17249
|
action: "transfer"
|
|
16924
17250
|
});
|
|
16925
17251
|
try {
|
|
16926
|
-
logger$
|
|
17252
|
+
logger$15.debug("[WebRTCManager] Transferring call with options:", options);
|
|
16927
17253
|
await this.executeVerto(message);
|
|
16928
17254
|
} catch (error) {
|
|
16929
|
-
logger$
|
|
17255
|
+
logger$15.error("[WebRTCManager] Error transferring call:", error);
|
|
16930
17256
|
throw error;
|
|
16931
17257
|
}
|
|
16932
17258
|
}
|
|
@@ -16940,6 +17266,77 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16940
17266
|
}
|
|
16941
17267
|
};
|
|
16942
17268
|
|
|
17269
|
+
//#endregion
|
|
17270
|
+
//#region src/controllers/RemoteAudioMeter.ts
|
|
17271
|
+
var import_cjs$14 = require_cjs();
|
|
17272
|
+
const logger$14 = getLogger();
|
|
17273
|
+
/**
|
|
17274
|
+
* Read-only audio level meter for a remote MediaStream. Attaches an
|
|
17275
|
+
* AnalyserNode to a MediaStreamAudioSourceNode so it observes the stream
|
|
17276
|
+
* without affecting the caller's playback path (no GainNode, no destination).
|
|
17277
|
+
*
|
|
17278
|
+
* The server delivers all remote audio as a single mixed stream — there is
|
|
17279
|
+
* no per-participant demux — so this meter reports the aggregate remote
|
|
17280
|
+
* level, not per-member.
|
|
17281
|
+
*/
|
|
17282
|
+
var RemoteAudioMeter = class extends Destroyable {
|
|
17283
|
+
constructor(options = {}) {
|
|
17284
|
+
super();
|
|
17285
|
+
this._source = null;
|
|
17286
|
+
this._stream = null;
|
|
17287
|
+
this._audioContext = (options.audioContextFactory ?? (() => new AudioContext()))();
|
|
17288
|
+
this._analyser = this._audioContext.createAnalyser();
|
|
17289
|
+
this._analyser.fftSize = 2048;
|
|
17290
|
+
this._analyser.smoothingTimeConstant = .3;
|
|
17291
|
+
this._analyserBuffer = new Uint8Array(new ArrayBuffer(this._analyser.fftSize));
|
|
17292
|
+
this._pollIntervalMs = options.pollIntervalMs ?? AUDIO_LEVEL_POLL_INTERVAL_MS;
|
|
17293
|
+
}
|
|
17294
|
+
/** RMS level of the remote audio, 0..1. 0 when no stream is attached. */
|
|
17295
|
+
get level$() {
|
|
17296
|
+
return this.deferEmission((0, import_cjs$14.interval)(this._pollIntervalMs, import_cjs$14.animationFrameScheduler).pipe((0, import_cjs$14.map)(() => this.computeLevel())));
|
|
17297
|
+
}
|
|
17298
|
+
/**
|
|
17299
|
+
* Attach (or replace) the MediaStream whose audio track is being metered.
|
|
17300
|
+
* Pass null to detach without destroying the meter.
|
|
17301
|
+
*/
|
|
17302
|
+
setStream(stream) {
|
|
17303
|
+
if (this._source) {
|
|
17304
|
+
try {
|
|
17305
|
+
this._source.disconnect();
|
|
17306
|
+
} catch (error) {
|
|
17307
|
+
logger$14.debug("[RemoteAudioMeter] source disconnect warning:", error);
|
|
17308
|
+
}
|
|
17309
|
+
this._source = null;
|
|
17310
|
+
this._stream = null;
|
|
17311
|
+
}
|
|
17312
|
+
if (!stream || stream.getAudioTracks().length === 0) return;
|
|
17313
|
+
this._stream = new MediaStream(stream.getAudioTracks());
|
|
17314
|
+
this._source = this._audioContext.createMediaStreamSource(this._stream);
|
|
17315
|
+
}
|
|
17316
|
+
destroy() {
|
|
17317
|
+
if (this._source) {
|
|
17318
|
+
try {
|
|
17319
|
+
this._source.disconnect();
|
|
17320
|
+
} catch {}
|
|
17321
|
+
this._source = null;
|
|
17322
|
+
}
|
|
17323
|
+
this._audioContext.close().catch((error) => {
|
|
17324
|
+
logger$14.debug("[RemoteAudioMeter] audio context close warning:", error);
|
|
17325
|
+
});
|
|
17326
|
+
super.destroy();
|
|
17327
|
+
}
|
|
17328
|
+
computeLevel() {
|
|
17329
|
+
if (!this._source) return 0;
|
|
17330
|
+
this._analyser.getByteTimeDomainData(this._analyserBuffer);
|
|
17331
|
+
let sum = 0;
|
|
17332
|
+
for (const sample$1 of this._analyserBuffer) {
|
|
17333
|
+
const normalized = (sample$1 - 128) / 128;
|
|
17334
|
+
sum += normalized * normalized;
|
|
17335
|
+
}
|
|
17336
|
+
return Math.sqrt(sum / this._analyserBuffer.length);
|
|
17337
|
+
}
|
|
17338
|
+
};
|
|
17339
|
+
|
|
16943
17340
|
//#endregion
|
|
16944
17341
|
//#region src/controllers/RTCStatsMonitor.ts
|
|
16945
17342
|
var import_cjs$13 = require_cjs();
|
|
@@ -17097,11 +17494,11 @@ var RTCStatsMonitor = class extends Destroyable {
|
|
|
17097
17494
|
let availableOutgoingBitrate;
|
|
17098
17495
|
report.forEach((stat) => {
|
|
17099
17496
|
if (isInboundRtpStat(stat)) if (stat.kind === "audio") {
|
|
17100
|
-
audioPacketsReceived += stat.packetsReceived ??
|
|
17497
|
+
audioPacketsReceived += stat.packetsReceived ?? 0;
|
|
17101
17498
|
audioPacketsLost += stat.packetsLost ?? 0;
|
|
17102
17499
|
audioJitter = Math.max(audioJitter, (stat.jitter ?? 0) * 1e3);
|
|
17103
17500
|
} else {
|
|
17104
|
-
videoPacketsReceived += stat.packetsReceived ??
|
|
17501
|
+
videoPacketsReceived += stat.packetsReceived ?? 0;
|
|
17105
17502
|
videoPacketsLost += stat.packetsLost ?? 0;
|
|
17106
17503
|
}
|
|
17107
17504
|
if (isCandidatePairStat(stat) && stat.state === "succeeded" && stat.nominated) {
|
|
@@ -17753,6 +18150,8 @@ var WebRTCCall = class extends Destroyable {
|
|
|
17753
18150
|
this._bandwidthConstrained$ = this.createBehaviorSubject(false);
|
|
17754
18151
|
this._mediaParamsUpdated$ = this.createSubject();
|
|
17755
18152
|
this._customSubscriptions = /* @__PURE__ */ new Map();
|
|
18153
|
+
this._pushToTalkEnabled = false;
|
|
18154
|
+
this._remoteAudioMeter = null;
|
|
17756
18155
|
this.id = options.callId ?? v4_default();
|
|
17757
18156
|
this.to = options.to;
|
|
17758
18157
|
this._userVariables$.next({
|
|
@@ -18151,10 +18550,10 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18151
18550
|
try {
|
|
18152
18551
|
if (this.vertoManager.requestIceRestartAll) await this.vertoManager.requestIceRestartAll(relayOnly);
|
|
18153
18552
|
else await this.vertoManager.requestIceRestart?.(relayOnly);
|
|
18154
|
-
return true;
|
|
18155
18553
|
} catch {
|
|
18156
18554
|
return false;
|
|
18157
18555
|
}
|
|
18556
|
+
return this.waitForPeerConnectionConnected();
|
|
18158
18557
|
},
|
|
18159
18558
|
disableVideo: () => {
|
|
18160
18559
|
try {
|
|
@@ -18246,6 +18645,27 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18246
18645
|
}
|
|
18247
18646
|
}
|
|
18248
18647
|
/**
|
|
18648
|
+
* Wait for the underlying RTCPeerConnection to reach 'connected' after
|
|
18649
|
+
* triggering an ICE restart. Resolves true on success, false on failure
|
|
18650
|
+
* or if the state doesn't transition within the configured timeout.
|
|
18651
|
+
*
|
|
18652
|
+
* Polls connectionState directly because the recovery manager already
|
|
18653
|
+
* wraps this call in its own withTimeout(); a separate listener-based
|
|
18654
|
+
* implementation would race the outer timeout in subtle ways.
|
|
18655
|
+
*/
|
|
18656
|
+
async waitForPeerConnectionConnected() {
|
|
18657
|
+
const pc = this.rtcPeerConnection;
|
|
18658
|
+
if (!pc) return false;
|
|
18659
|
+
const deadline = Date.now() + PEER_CONNECTION_RECOVERY_WAIT_MS;
|
|
18660
|
+
for (;;) {
|
|
18661
|
+
const state = pc.connectionState;
|
|
18662
|
+
if (state === "connected") return true;
|
|
18663
|
+
if (state === "failed" || state === "closed") return false;
|
|
18664
|
+
if (Date.now() >= deadline) return false;
|
|
18665
|
+
await new Promise((resolve) => setTimeout(resolve, PEER_CONNECTION_RECOVERY_POLL_MS));
|
|
18666
|
+
}
|
|
18667
|
+
}
|
|
18668
|
+
/**
|
|
18249
18669
|
* @internal Stop and destroy resilience subsystems (on disconnect/destroy).
|
|
18250
18670
|
* Clears references so they can be re-created on reconnect.
|
|
18251
18671
|
*/
|
|
@@ -18382,8 +18802,13 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18382
18802
|
const cached = this._customSubscriptions.get(eventType);
|
|
18383
18803
|
if (cached) return cached;
|
|
18384
18804
|
const filtered$ = this.callSessionEvents$.pipe((0, import_cjs$11.filter)((event) => event.event_type === eventType), (0, import_cjs$11.map)((event) => JSON.parse(JSON.stringify(event))), (0, import_cjs$11.takeUntil)(this._destroyed$));
|
|
18805
|
+
this._sendVertoSubscribe(eventType).then(() => {
|
|
18806
|
+
this._customSubscriptions.set(eventType, filtered$);
|
|
18807
|
+
}, (error) => {
|
|
18808
|
+
this._customSubscriptions.delete(eventType);
|
|
18809
|
+
logger$11.warn(`[Call] verto.subscribe for '${eventType}' failed, not caching:`, error);
|
|
18810
|
+
});
|
|
18385
18811
|
this._customSubscriptions.set(eventType, filtered$);
|
|
18386
|
-
this._sendVertoSubscribe(eventType);
|
|
18387
18812
|
return filtered$;
|
|
18388
18813
|
}
|
|
18389
18814
|
get webrtcMessages$() {
|
|
@@ -18498,37 +18923,156 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18498
18923
|
async transfer(options) {
|
|
18499
18924
|
return this.vertoManager.transfer(options);
|
|
18500
18925
|
}
|
|
18926
|
+
/**
|
|
18927
|
+
* Set the local microphone gain as a percentage applied before transmission.
|
|
18928
|
+
*
|
|
18929
|
+
* - `0` = silent
|
|
18930
|
+
* - `100` = unity (no change, default)
|
|
18931
|
+
* - `200` = 2× digital boost (max; expect clipping / noise amplification)
|
|
18932
|
+
*
|
|
18933
|
+
* Values are clamped to [0, 200]. Engages the local audio pipeline on
|
|
18934
|
+
* first use (one-time cost).
|
|
18935
|
+
*
|
|
18936
|
+
* Note: this is a **digital** multiplier applied in a Web Audio GainNode
|
|
18937
|
+
* between your mic track and the RTCRtpSender — it does not change the
|
|
18938
|
+
* physical mic's hardware sensitivity. Browsers' autoGainControl can
|
|
18939
|
+
* fight the setting; call {@link setAutoGainControl}(false) for
|
|
18940
|
+
* predictable behaviour.
|
|
18941
|
+
*
|
|
18942
|
+
* @param value - Gain percentage (0..200; 100 = unity).
|
|
18943
|
+
*/
|
|
18944
|
+
setLocalMicrophoneGain(value) {
|
|
18945
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18946
|
+
if (!pipeline) {
|
|
18947
|
+
logger$11.warn("[Call] setLocalMicrophoneGain: audio pipeline unavailable");
|
|
18948
|
+
return;
|
|
18949
|
+
}
|
|
18950
|
+
const percent = Math.max(0, Math.min(200, value));
|
|
18951
|
+
pipeline.setGain(percent / 100);
|
|
18952
|
+
}
|
|
18953
|
+
/** Observable of the current local microphone gain (0..200, where 100 = unity). */
|
|
18954
|
+
get localMicrophoneGain$() {
|
|
18955
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18956
|
+
if (!pipeline) return (0, import_cjs$11.of)(100).pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
|
|
18957
|
+
return this.publicCachedObservable("localMicrophoneGain$", () => pipeline.gain$.pipe((0, import_cjs$11.map)((multiplier) => multiplier * 100), (0, import_cjs$11.takeUntil)(this._destroyed$)));
|
|
18958
|
+
}
|
|
18959
|
+
/**
|
|
18960
|
+
* Observable of the RMS audio level of the local microphone, 0..1.
|
|
18961
|
+
* Emits at ~30fps while a mic track is active. Engages the local audio
|
|
18962
|
+
* pipeline on first subscription.
|
|
18963
|
+
*/
|
|
18964
|
+
get localAudioLevel$() {
|
|
18965
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18966
|
+
if (!pipeline) return (0, import_cjs$11.of)(0).pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
|
|
18967
|
+
return this.publicCachedObservable("localAudioLevel$", () => pipeline.level$.pipe((0, import_cjs$11.takeUntil)(this._destroyed$), (0, import_cjs$11.share)()));
|
|
18968
|
+
}
|
|
18969
|
+
/**
|
|
18970
|
+
* Observable that is `true` while the local participant is speaking
|
|
18971
|
+
* (RMS level above the VAD threshold, with hold time to avoid flicker).
|
|
18972
|
+
*/
|
|
18973
|
+
get localSpeaking$() {
|
|
18974
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18975
|
+
if (!pipeline) return (0, import_cjs$11.of)(false).pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
|
|
18976
|
+
return this.publicCachedObservable("localSpeaking$", () => pipeline.speaking$.pipe((0, import_cjs$11.takeUntil)(this._destroyed$), (0, import_cjs$11.share)()));
|
|
18977
|
+
}
|
|
18978
|
+
/**
|
|
18979
|
+
* Enable push-to-talk: while {@link setPushToTalkActive} has been called
|
|
18980
|
+
* with `false`, the microphone gain is forced to 0; calling
|
|
18981
|
+
* {@link setPushToTalkActive} with `true` restores the configured gain.
|
|
18982
|
+
* Use this instead of mute/unmute for instant talk/silence transitions
|
|
18983
|
+
* because it doesn't rebuild the track.
|
|
18984
|
+
*
|
|
18985
|
+
* This method installs the pipeline but does not attach any keyboard
|
|
18986
|
+
* listener — consumers bind the key themselves and call
|
|
18987
|
+
* {@link setPushToTalkActive} on keydown/keyup.
|
|
18988
|
+
*/
|
|
18989
|
+
enablePushToTalk() {
|
|
18990
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18991
|
+
if (!pipeline) {
|
|
18992
|
+
logger$11.warn("[Call] enablePushToTalk: audio pipeline unavailable");
|
|
18993
|
+
return;
|
|
18994
|
+
}
|
|
18995
|
+
pipeline.setPTTActive(false);
|
|
18996
|
+
this._pushToTalkEnabled = true;
|
|
18997
|
+
}
|
|
18998
|
+
/** Disable push-to-talk; mic gain returns to the configured value. */
|
|
18999
|
+
disablePushToTalk() {
|
|
19000
|
+
this.vertoManager.localAudioPipeline?.setPTTActive(true);
|
|
19001
|
+
this._pushToTalkEnabled = false;
|
|
19002
|
+
}
|
|
19003
|
+
/**
|
|
19004
|
+
* While push-to-talk is enabled, sets the talk state. `true` = transmitting,
|
|
19005
|
+
* `false` = silent. No-op if push-to-talk has not been enabled.
|
|
19006
|
+
*/
|
|
19007
|
+
setPushToTalkActive(active) {
|
|
19008
|
+
if (!this._pushToTalkEnabled) return;
|
|
19009
|
+
this.vertoManager.localAudioPipeline?.setPTTActive(active);
|
|
19010
|
+
}
|
|
19011
|
+
/**
|
|
19012
|
+
* Toggle echo cancellation on the local mic at runtime. Applied via
|
|
19013
|
+
* `track.applyConstraints`; browsers that don't honour runtime constraints
|
|
19014
|
+
* (notably iOS Safari) fall back to re-acquiring the track with the new
|
|
19015
|
+
* constraint set and plumbing the replacement through the local audio
|
|
19016
|
+
* pipeline if one is active.
|
|
19017
|
+
*/
|
|
19018
|
+
async setEchoCancellation(enabled) {
|
|
19019
|
+
await this.vertoManager.updateMediaConstraints({ audio: { echoCancellation: enabled } });
|
|
19020
|
+
}
|
|
19021
|
+
/** Toggle browser noise suppression on the local mic at runtime. */
|
|
19022
|
+
async setNoiseSuppression(enabled) {
|
|
19023
|
+
await this.vertoManager.updateMediaConstraints({ audio: { noiseSuppression: enabled } });
|
|
19024
|
+
}
|
|
19025
|
+
/** Toggle browser automatic gain control on the local mic at runtime. */
|
|
19026
|
+
async setAutoGainControl(enabled) {
|
|
19027
|
+
await this.vertoManager.updateMediaConstraints({ audio: { autoGainControl: enabled } });
|
|
19028
|
+
}
|
|
19029
|
+
/**
|
|
19030
|
+
* Observable of the aggregate remote audio level, 0..1 RMS. The server
|
|
19031
|
+
* delivers a single mixed audio stream for all remote participants — this
|
|
19032
|
+
* meter reports that mix. Per-participant audio is not available client-side.
|
|
19033
|
+
*
|
|
19034
|
+
* Engages a shared AudioContext on first subscription (cheap — one
|
|
19035
|
+
* AnalyserNode, no GainNode, no destination) so it does not affect the
|
|
19036
|
+
* caller's audio element playback.
|
|
19037
|
+
*/
|
|
19038
|
+
get remoteAudioLevel$() {
|
|
19039
|
+
return this.publicCachedObservable("remoteAudioLevel$", () => {
|
|
19040
|
+
this._remoteAudioMeter ??= new RemoteAudioMeter();
|
|
19041
|
+
const meter = this._remoteAudioMeter;
|
|
19042
|
+
this.subscribeTo(this.vertoManager.remoteStream$, (stream) => {
|
|
19043
|
+
meter.setStream(stream);
|
|
19044
|
+
});
|
|
19045
|
+
return meter.level$.pipe((0, import_cjs$11.takeUntil)(this._destroyed$), (0, import_cjs$11.share)());
|
|
19046
|
+
});
|
|
19047
|
+
}
|
|
18501
19048
|
/** Destroys the call, releasing all resources and subscriptions. */
|
|
18502
19049
|
destroy() {
|
|
18503
19050
|
if (this._status$.value === "destroyed") return;
|
|
18504
19051
|
this._status$.next("destroyed");
|
|
18505
19052
|
this.stopResilienceSubsystems();
|
|
19053
|
+
this._remoteAudioMeter?.destroy();
|
|
19054
|
+
this._remoteAudioMeter = null;
|
|
18506
19055
|
this.vertoManager.destroy();
|
|
18507
19056
|
this.callEventsManager.destroy();
|
|
18508
19057
|
super.destroy();
|
|
18509
19058
|
}
|
|
18510
19059
|
/**
|
|
18511
19060
|
* @internal Send a verto.subscribe message to add an event type to the
|
|
18512
|
-
* server's subscription list for this call.
|
|
18513
|
-
*
|
|
19061
|
+
* server's subscription list for this call. Returns the underlying RPC
|
|
19062
|
+
* promise so callers can decide whether to cache the observable on success
|
|
19063
|
+
* or retry on failure.
|
|
18514
19064
|
*/
|
|
18515
|
-
_sendVertoSubscribe(eventType) {
|
|
18516
|
-
|
|
18517
|
-
|
|
18518
|
-
|
|
18519
|
-
|
|
18520
|
-
|
|
18521
|
-
|
|
18522
|
-
|
|
18523
|
-
|
|
18524
|
-
|
|
18525
|
-
|
|
18526
|
-
this.clientSession.execute(WebrtcVerto(params)).catch((error) => {
|
|
18527
|
-
logger$11.warn(`[Call] verto.subscribe for '${eventType}' failed (non-fatal):`, error);
|
|
18528
|
-
});
|
|
18529
|
-
} catch (error) {
|
|
18530
|
-
logger$11.warn(`[Call] Failed to send verto.subscribe for '${eventType}':`, error);
|
|
18531
|
-
}
|
|
19065
|
+
async _sendVertoSubscribe(eventType) {
|
|
19066
|
+
const message = VertoSubscribe({
|
|
19067
|
+
sessid: this.id,
|
|
19068
|
+
eventChannel: [eventType]
|
|
19069
|
+
});
|
|
19070
|
+
const params = {
|
|
19071
|
+
callID: this.id,
|
|
19072
|
+
node_id: this.vertoManager.nodeId ?? "",
|
|
19073
|
+
message
|
|
19074
|
+
};
|
|
19075
|
+
await this.clientSession.execute(WebrtcVerto(params));
|
|
18532
19076
|
}
|
|
18533
19077
|
};
|
|
18534
19078
|
|
|
@@ -18545,11 +19089,21 @@ function inferCallErrorKind(error) {
|
|
|
18545
19089
|
if (error instanceof WebSocketConnectionError || error instanceof TransportConnectionError) return "network";
|
|
18546
19090
|
return "internal";
|
|
18547
19091
|
}
|
|
19092
|
+
/** JSON-RPC error codes that ClientSessionManager treats as recoverable at the
|
|
19093
|
+
* session level. Surfacing one of these against an in-flight call should not
|
|
19094
|
+
* destroy the call, because the session will reauthenticate and any pending
|
|
19095
|
+
* RPC can then be retried. */
|
|
19096
|
+
const RECOVERABLE_RPC_CODES = new Set([
|
|
19097
|
+
RPC_ERROR_REQUESTER_VALIDATION_FAILED,
|
|
19098
|
+
RPC_ERROR_AUTHENTICATION_FAILED,
|
|
19099
|
+
RPC_ERROR_INVALID_PARAMS
|
|
19100
|
+
]);
|
|
18548
19101
|
/** Determines whether an error should be fatal (destroy the call). */
|
|
18549
19102
|
function isFatalError(error) {
|
|
18550
19103
|
if (error instanceof VertoPongError) return false;
|
|
18551
19104
|
if (error instanceof MediaTrackError) return false;
|
|
18552
19105
|
if (error instanceof RPCTimeoutError) return false;
|
|
19106
|
+
if (error instanceof JSONRPCError && RECOVERABLE_RPC_CODES.has(error.code)) return false;
|
|
18553
19107
|
return true;
|
|
18554
19108
|
}
|
|
18555
19109
|
/**
|
|
@@ -18987,10 +19541,10 @@ var PendingRPC = class PendingRPC {
|
|
|
18987
19541
|
}
|
|
18988
19542
|
let isSettled = false;
|
|
18989
19543
|
const subscription = (0, import_cjs$8.race)(responses$.pipe((0, import_cjs$8.filter)((result) => result.id === request.id), (0, import_cjs$8.take)(1)), new import_cjs$8.Observable((subscriber) => {
|
|
18990
|
-
const timer$
|
|
19544
|
+
const timer$4 = setTimeout(() => {
|
|
18991
19545
|
subscriber.error(new RPCTimeoutError(request.id, timeoutMs));
|
|
18992
19546
|
}, timeoutMs);
|
|
18993
|
-
return () => clearTimeout(timer$
|
|
19547
|
+
return () => clearTimeout(timer$4);
|
|
18994
19548
|
}), signal ? new import_cjs$8.Observable((subscriber) => {
|
|
18995
19549
|
const abortHandler = () => {
|
|
18996
19550
|
subscriber.error(new DOMException("The operation was aborted", "AbortError"));
|
|
@@ -19056,7 +19610,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19056
19610
|
this.attachManager = attachManager;
|
|
19057
19611
|
this.dpopManager = dpopManager;
|
|
19058
19612
|
this.callCreateTimeout = 6e3;
|
|
19059
|
-
this.agent = `signalwire-
|
|
19613
|
+
this.agent = `signalwire-js/4.0.0`;
|
|
19060
19614
|
this.eventAcks = true;
|
|
19061
19615
|
this.authorizationState$ = this.createReplaySubject(1);
|
|
19062
19616
|
this.connectVersion = {
|
|
@@ -19068,7 +19622,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19068
19622
|
this._errors$ = this.createReplaySubject(1);
|
|
19069
19623
|
this._authState$ = this.createBehaviorSubject({ kind: "unauthenticated" });
|
|
19070
19624
|
this._wasClientBound = false;
|
|
19071
|
-
this.
|
|
19625
|
+
this._userInfo$ = this.createBehaviorSubject(null);
|
|
19072
19626
|
this._calls$ = this.createBehaviorSubject({});
|
|
19073
19627
|
this._iceServers$ = this.createBehaviorSubject([]);
|
|
19074
19628
|
attachManager.setSession(this);
|
|
@@ -19081,11 +19635,11 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19081
19635
|
get incomingCalls() {
|
|
19082
19636
|
return Object.values(this._calls$.value).filter((call) => call.direction === "inbound");
|
|
19083
19637
|
}
|
|
19084
|
-
get
|
|
19085
|
-
return this.
|
|
19638
|
+
get userInfo$() {
|
|
19639
|
+
return this._userInfo$.asObservable();
|
|
19086
19640
|
}
|
|
19087
|
-
get
|
|
19088
|
-
return this.
|
|
19641
|
+
get userInfo() {
|
|
19642
|
+
return this._userInfo$.value;
|
|
19089
19643
|
}
|
|
19090
19644
|
get calls$() {
|
|
19091
19645
|
return this.cachedObservable("calls$", () => this._calls$.pipe((0, import_cjs$7.map)((calls) => Object.values(calls))));
|
|
@@ -19390,7 +19944,6 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19390
19944
|
displayDirection: invite.display_direction,
|
|
19391
19945
|
userVariables: invite.userVariables
|
|
19392
19946
|
});
|
|
19393
|
-
await (0, import_cjs$7.firstValueFrom)(callSession.status$);
|
|
19394
19947
|
this._calls$.next({
|
|
19395
19948
|
[`${callSession.id}`]: callSession,
|
|
19396
19949
|
...this._calls$.value
|
|
@@ -19411,7 +19964,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19411
19964
|
logger$8.debug(`[Session] Verto attach for existing call ${callID}, deferring to per-call handler`);
|
|
19412
19965
|
return;
|
|
19413
19966
|
}
|
|
19414
|
-
const storedOptions = this.attachManager.consumePendingAttachment(callID);
|
|
19967
|
+
const storedOptions = await this.attachManager.consumePendingAttachment(callID);
|
|
19415
19968
|
logger$8.debug(`[Session] Creating reattached call for callID: ${callID}`);
|
|
19416
19969
|
const callSession = await this.createCall({
|
|
19417
19970
|
nodeId: attach.node_id,
|
|
@@ -19423,7 +19976,6 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19423
19976
|
reattach: true,
|
|
19424
19977
|
...storedOptions
|
|
19425
19978
|
});
|
|
19426
|
-
await (0, import_cjs$7.firstValueFrom)(callSession.status$);
|
|
19427
19979
|
this._calls$.next({
|
|
19428
19980
|
[`${callSession.id}`]: callSession,
|
|
19429
19981
|
...this._calls$.value
|
|
@@ -19533,22 +20085,22 @@ var ConversationMessageCollection = class extends EntityCollection {
|
|
|
19533
20085
|
}
|
|
19534
20086
|
};
|
|
19535
20087
|
var ConversationsManager = class {
|
|
19536
|
-
constructor(clientSession, http,
|
|
20088
|
+
constructor(clientSession, http, getUserAddressId, onError) {
|
|
19537
20089
|
this.clientSession = clientSession;
|
|
19538
20090
|
this.http = http;
|
|
19539
|
-
this.
|
|
20091
|
+
this.getUserAddressId = getUserAddressId;
|
|
19540
20092
|
this.onError = onError;
|
|
19541
20093
|
this.groupIds = /* @__PURE__ */ new Map();
|
|
19542
20094
|
}
|
|
19543
20095
|
async join(addressId) {
|
|
19544
|
-
const
|
|
20096
|
+
const userFromAddressId = this.getUserAddressId();
|
|
19545
20097
|
try {
|
|
19546
20098
|
const response = await this.http.request({
|
|
19547
20099
|
...POST_PARAMS,
|
|
19548
20100
|
url: `/api/fabric/conversations/join`,
|
|
19549
20101
|
body: JSON.stringify({
|
|
19550
|
-
from_fabric_address_id:
|
|
19551
|
-
fabric_address_ids: [addressId,
|
|
20102
|
+
from_fabric_address_id: userFromAddressId,
|
|
20103
|
+
fabric_address_ids: [addressId, userFromAddressId]
|
|
19552
20104
|
})
|
|
19553
20105
|
});
|
|
19554
20106
|
if (response.ok && !!response.body) {
|
|
@@ -19570,14 +20122,14 @@ var ConversationsManager = class {
|
|
|
19570
20122
|
}
|
|
19571
20123
|
async sendText(text, destinationAddressId) {
|
|
19572
20124
|
const groupId = this.groupIds.get(destinationAddressId) ?? await this.join(destinationAddressId);
|
|
19573
|
-
const
|
|
20125
|
+
const userFromAddressId = this.getUserAddressId();
|
|
19574
20126
|
try {
|
|
19575
20127
|
if ((await this.http.request({
|
|
19576
20128
|
...POST_PARAMS,
|
|
19577
20129
|
url: "/api/fabric/messages",
|
|
19578
20130
|
body: JSON.stringify({
|
|
19579
20131
|
group_id: groupId,
|
|
19580
|
-
from_fabric_address_id:
|
|
20132
|
+
from_fabric_address_id: userFromAddressId,
|
|
19581
20133
|
text
|
|
19582
20134
|
})
|
|
19583
20135
|
})).ok) return;
|
|
@@ -19650,17 +20202,17 @@ var DeviceTokenManager = class extends Destroyable {
|
|
|
19650
20202
|
return this._effectiveExpireIn;
|
|
19651
20203
|
}
|
|
19652
20204
|
/**
|
|
19653
|
-
* Activates the Client Bound SAT flow when the
|
|
20205
|
+
* Activates the Client Bound SAT flow when the user's token has
|
|
19654
20206
|
* `sat:refresh` scope.
|
|
19655
20207
|
*
|
|
19656
20208
|
* Steps:
|
|
19657
|
-
* 1. Check
|
|
20209
|
+
* 1. Check user's `sat_claims` for `sat:refresh` scope
|
|
19658
20210
|
* 2. Call `/api/fabric/subscriber/devices/token` with a DPoP proof
|
|
19659
20211
|
* 3. Reauthenticate the session with the Client Bound SAT + DPoP proof
|
|
19660
20212
|
* 4. Emit token to trigger the reactive refresh pipeline
|
|
19661
20213
|
*/
|
|
19662
|
-
async activate(
|
|
19663
|
-
const { satClaims } =
|
|
20214
|
+
async activate(user, session, updateCredential) {
|
|
20215
|
+
const { satClaims } = user;
|
|
19664
20216
|
if (!satClaims?.scope?.includes(SAT_REFRESH_SCOPE)) {
|
|
19665
20217
|
logger$6.debug("[DeviceToken] No sat:refresh scope, skipping Client Bound SAT activation");
|
|
19666
20218
|
return;
|
|
@@ -19943,9 +20495,9 @@ const isEmptyArray = (a) => {
|
|
|
19943
20495
|
};
|
|
19944
20496
|
|
|
19945
20497
|
//#endregion
|
|
19946
|
-
//#region src/utils/
|
|
20498
|
+
//#region src/utils/warmup.ts
|
|
19947
20499
|
var import_cjs$4 = require_cjs();
|
|
19948
|
-
const
|
|
20500
|
+
const warmup = (observable) => {
|
|
19949
20501
|
observable.pipe((0, import_cjs$4.take)(1)).subscribe();
|
|
19950
20502
|
};
|
|
19951
20503
|
|
|
@@ -19994,7 +20546,7 @@ var DirectoryManager = class extends Destroyable {
|
|
|
19994
20546
|
return address;
|
|
19995
20547
|
}));
|
|
19996
20548
|
if (observable) {
|
|
19997
|
-
|
|
20549
|
+
warmup(observable);
|
|
19998
20550
|
this._observableRegistry.set(id, observable);
|
|
19999
20551
|
}
|
|
20000
20552
|
this._addressesInstances.set(id, address);
|
|
@@ -20146,10 +20698,9 @@ var WebSocketController = class WebSocketController extends Destroyable {
|
|
|
20146
20698
|
else this._status$.next("disconnected");
|
|
20147
20699
|
}
|
|
20148
20700
|
reconnect() {
|
|
20149
|
-
|
|
20150
|
-
|
|
20151
|
-
|
|
20152
|
-
} else this._status$.next("disconnected");
|
|
20701
|
+
this.shouldReconnect = true;
|
|
20702
|
+
this._status$.next("reconnecting");
|
|
20703
|
+
this.scheduleReconnection();
|
|
20153
20704
|
}
|
|
20154
20705
|
send(data) {
|
|
20155
20706
|
if (this._status$.value === "connected" && this.socket?.readyState === 1) {
|
|
@@ -20508,7 +21059,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20508
21059
|
constructor(credentialProvider, options = {}) {
|
|
20509
21060
|
super();
|
|
20510
21061
|
this.preferences = new ClientPreferences();
|
|
20511
|
-
this.
|
|
21062
|
+
this._user$ = this.createBehaviorSubject(void 0);
|
|
20512
21063
|
this._directory$ = this.createBehaviorSubject(void 0);
|
|
20513
21064
|
this._isConnected$ = this.createBehaviorSubject(false);
|
|
20514
21065
|
this._isRegistered$ = this.createBehaviorSubject(false);
|
|
@@ -20648,7 +21199,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20648
21199
|
if (this._deps.persistSession) this._deps.storage.setItem("sw:cached_credential", credential, "local");
|
|
20649
21200
|
}
|
|
20650
21201
|
async init() {
|
|
20651
|
-
this.
|
|
21202
|
+
this._user$.next(new User(this._deps.http));
|
|
20652
21203
|
if (!this._options.skipConnection) await this.connect();
|
|
20653
21204
|
if (!this._options.reconnectAttachedCalls && this._attachManager) await this._attachManager.flush();
|
|
20654
21205
|
if (!this._options.skipRegister) try {
|
|
@@ -20710,14 +21261,15 @@ var SignalWire = class extends Destroyable {
|
|
|
20710
21261
|
* `'reconnecting'`, `'disconnecting'`, or `'disconnected'`.
|
|
20711
21262
|
*/
|
|
20712
21263
|
async connect() {
|
|
21264
|
+
await this.teardownTransportAndSession();
|
|
20713
21265
|
try {
|
|
20714
|
-
const
|
|
20715
|
-
if (!
|
|
20716
|
-
if (!await (0, import_cjs$1.firstValueFrom)(
|
|
20717
|
-
this._deps.
|
|
21266
|
+
const user = this._user$.value;
|
|
21267
|
+
if (!user) throw new UnexpectedError("User not initialized before connect");
|
|
21268
|
+
if (!await (0, import_cjs$1.firstValueFrom)(user.fetched$)) throw new UnexpectedError("Failed to fetch user information - fetched$ emitted false");
|
|
21269
|
+
this._deps.user = user;
|
|
20718
21270
|
} catch (error) {
|
|
20719
|
-
logger$1.error(`[SignalWire] Failed to fetch
|
|
20720
|
-
throw new UnexpectedError("Error fetching
|
|
21271
|
+
logger$1.error(`[SignalWire] Failed to fetch user information: ${error instanceof Error ? error.message : "Unknown error"}. This usually means the user token is invalid or expired.`);
|
|
21272
|
+
throw new UnexpectedError("Error fetching user information", { cause: error });
|
|
20721
21273
|
}
|
|
20722
21274
|
const errorHandler = (error) => {
|
|
20723
21275
|
this._errors$.next(error);
|
|
@@ -20751,7 +21303,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20751
21303
|
logger$1.debug("[SignalWire] Developer refresh disabled — Client Bound SAT activation starting");
|
|
20752
21304
|
}
|
|
20753
21305
|
this._deviceTokenManager = new DeviceTokenManager(this._dpopManager, this._deps.http, (error) => this._errors$.next(error), () => this._deps.credential);
|
|
20754
|
-
await this._deviceTokenManager.activate(this._deps.
|
|
21306
|
+
await this._deviceTokenManager.activate(this._deps.user, this._clientSession, (cred) => {
|
|
20755
21307
|
this._deps.credential = {
|
|
20756
21308
|
...this._deps.credential,
|
|
20757
21309
|
...cred
|
|
@@ -20761,7 +21313,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20761
21313
|
this.subscribeTo(this._clientSession.authenticated$.pipe((0, import_cjs$1.skip)(1), (0, import_cjs$1.filter)(Boolean)), async () => {
|
|
20762
21314
|
try {
|
|
20763
21315
|
if (this._deviceTokenManager) {
|
|
20764
|
-
await this._deviceTokenManager.activate(this._deps.
|
|
21316
|
+
await this._deviceTokenManager.activate(this._deps.user, this._clientSession, (cred) => {
|
|
20765
21317
|
this._deps.credential = {
|
|
20766
21318
|
...this._deps.credential,
|
|
20767
21319
|
...cred
|
|
@@ -20774,15 +21326,15 @@ var SignalWire = class extends Destroyable {
|
|
|
20774
21326
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
20775
21327
|
}
|
|
20776
21328
|
try {
|
|
20777
|
-
logger$1.debug("[SignalWire] Re-registering
|
|
21329
|
+
logger$1.debug("[SignalWire] Re-registering user after reconnect");
|
|
20778
21330
|
await this.register();
|
|
20779
|
-
logger$1.debug("[SignalWire]
|
|
21331
|
+
logger$1.debug("[SignalWire] User re-registered successfully after reconnect");
|
|
20780
21332
|
} catch (error) {
|
|
20781
21333
|
logger$1.error("[SignalWire] Re-registration failed after reconnect:", error);
|
|
20782
21334
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
20783
21335
|
}
|
|
20784
21336
|
});
|
|
20785
|
-
const conversationManager = new ConversationsManager(this._clientSession, this._deps.http, () => this._deps.
|
|
21337
|
+
const conversationManager = new ConversationsManager(this._clientSession, this._deps.http, () => this._deps.getUserFromAddressId(), errorHandler);
|
|
20786
21338
|
const directory = new DirectoryManager(this._deps.http, this._clientSession, conversationManager, errorHandler);
|
|
20787
21339
|
this._directory$.next(directory);
|
|
20788
21340
|
this._clientSession.setDirectory(directory);
|
|
@@ -20793,22 +21345,22 @@ var SignalWire = class extends Destroyable {
|
|
|
20793
21345
|
});
|
|
20794
21346
|
}
|
|
20795
21347
|
/**
|
|
20796
|
-
* Observable that emits the {@link
|
|
21348
|
+
* Observable that emits the {@link User} profile once fetched,
|
|
20797
21349
|
* or `undefined` before authentication completes.
|
|
20798
21350
|
*
|
|
20799
21351
|
* @example
|
|
20800
21352
|
* ```ts
|
|
20801
|
-
* client.
|
|
20802
|
-
* if (
|
|
21353
|
+
* client.user$.subscribe(u => {
|
|
21354
|
+
* if (u) console.log('Logged in as', u.email);
|
|
20803
21355
|
* });
|
|
20804
21356
|
* ```
|
|
20805
21357
|
*/
|
|
20806
|
-
get
|
|
20807
|
-
return this.deferEmission(this.
|
|
21358
|
+
get user$() {
|
|
21359
|
+
return this.deferEmission(this._user$.asObservable());
|
|
20808
21360
|
}
|
|
20809
|
-
/** Current
|
|
20810
|
-
get
|
|
20811
|
-
return this.
|
|
21361
|
+
/** Current user snapshot, or `undefined` if not yet authenticated. */
|
|
21362
|
+
get user() {
|
|
21363
|
+
return this._user$.value;
|
|
20812
21364
|
}
|
|
20813
21365
|
/**
|
|
20814
21366
|
* Observable that emits the {@link Directory} instance once the client is connected,
|
|
@@ -20832,11 +21384,11 @@ var SignalWire = class extends Destroyable {
|
|
|
20832
21384
|
get directory() {
|
|
20833
21385
|
return this._directory$.value;
|
|
20834
21386
|
}
|
|
20835
|
-
/** Observable that emits when the
|
|
21387
|
+
/** Observable that emits when the user registration state changes. */
|
|
20836
21388
|
get isRegistered$() {
|
|
20837
21389
|
return this.deferEmission(this._isRegistered$.asObservable());
|
|
20838
21390
|
}
|
|
20839
|
-
/** Whether the
|
|
21391
|
+
/** Whether the user is currently registered. */
|
|
20840
21392
|
get isRegistered() {
|
|
20841
21393
|
return this._isRegistered$.value;
|
|
20842
21394
|
}
|
|
@@ -20941,15 +21493,35 @@ var SignalWire = class extends Destroyable {
|
|
|
20941
21493
|
this._refreshTimerId = void 0;
|
|
20942
21494
|
}
|
|
20943
21495
|
this._diagnosticsCollector?.record("connection", "disconnected");
|
|
20944
|
-
await this.
|
|
20945
|
-
this._clientSession.destroy();
|
|
21496
|
+
await this.teardownTransportAndSession();
|
|
20946
21497
|
this._isConnected$.next(false);
|
|
20947
21498
|
}
|
|
21499
|
+
/**
|
|
21500
|
+
* Tear down the current transport / session / attach manager. Safe to call
|
|
21501
|
+
* when nothing has been initialized yet (e.g. first connect()).
|
|
21502
|
+
*/
|
|
21503
|
+
async teardownTransportAndSession() {
|
|
21504
|
+
const session = this._clientSession;
|
|
21505
|
+
const transport = this._transport;
|
|
21506
|
+
if (session) {
|
|
21507
|
+
try {
|
|
21508
|
+
await session.disconnect();
|
|
21509
|
+
} catch (error) {
|
|
21510
|
+
logger$1.warn("[SignalWire] Error disconnecting previous session:", error);
|
|
21511
|
+
}
|
|
21512
|
+
session.destroy();
|
|
21513
|
+
}
|
|
21514
|
+
if (transport) transport.destroy();
|
|
21515
|
+
this._clientSession = void 0;
|
|
21516
|
+
this._publicSession = void 0;
|
|
21517
|
+
this._transport = void 0;
|
|
21518
|
+
this._attachManager = void 0;
|
|
21519
|
+
}
|
|
20948
21520
|
async waitAuthentication() {
|
|
20949
21521
|
await (0, import_cjs$1.firstValueFrom)(this.ready$.pipe((0, import_cjs$1.filter)((ready$1) => ready$1 === true)));
|
|
20950
21522
|
}
|
|
20951
21523
|
/**
|
|
20952
|
-
* Registers the
|
|
21524
|
+
* Registers the user as online to receive inbound calls and events.
|
|
20953
21525
|
*
|
|
20954
21526
|
* Waits for authentication to complete before sending the registration.
|
|
20955
21527
|
* If the initial attempt fails, reauthentication is attempted automatically.
|
|
@@ -20964,26 +21536,31 @@ var SignalWire = class extends Destroyable {
|
|
|
20964
21536
|
params: {}
|
|
20965
21537
|
}));
|
|
20966
21538
|
this._isRegistered$.next(true);
|
|
21539
|
+
return;
|
|
20967
21540
|
} catch (error) {
|
|
20968
|
-
|
|
20969
|
-
|
|
21541
|
+
if (!this._deps.credential.token) {
|
|
21542
|
+
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
21543
|
+
throw error;
|
|
21544
|
+
}
|
|
21545
|
+
logger$1.debug("[SignalWire] Failed to register user, trying reauthentication...");
|
|
21546
|
+
try {
|
|
21547
|
+
await this._clientSession.reauthenticate(this._deps.credential.token);
|
|
20970
21548
|
logger$1.debug("[SignalWire] Reauthentication successful, retrying register()");
|
|
20971
21549
|
await this._transport.execute(RPCExecute({
|
|
20972
21550
|
method: "subscriber.online",
|
|
20973
21551
|
params: {}
|
|
20974
21552
|
}));
|
|
20975
21553
|
this._isRegistered$.next(true);
|
|
20976
|
-
}
|
|
21554
|
+
} catch (reauthError) {
|
|
20977
21555
|
logger$1.error("[SignalWire] Reauthentication failed during register():", reauthError);
|
|
20978
|
-
const registerError = new InvalidCredentialsError("Failed to register
|
|
21556
|
+
const registerError = new InvalidCredentialsError("Failed to register user, and reauthentication attempt also failed. Please check your credentials.", { cause: reauthError instanceof Error ? reauthError : new Error(String(reauthError), { cause: reauthError }) });
|
|
20979
21557
|
this._errors$.next(registerError);
|
|
20980
|
-
|
|
20981
|
-
|
|
20982
|
-
throw error;
|
|
21558
|
+
throw registerError;
|
|
21559
|
+
}
|
|
20983
21560
|
}
|
|
20984
21561
|
}
|
|
20985
21562
|
/**
|
|
20986
|
-
* Unregisters the
|
|
21563
|
+
* Unregisters the user, going offline for inbound calls.
|
|
20987
21564
|
*
|
|
20988
21565
|
* The WebSocket connection remains open; use {@link disconnect} to fully close it.
|
|
20989
21566
|
*/
|
|
@@ -20995,7 +21572,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20995
21572
|
}));
|
|
20996
21573
|
this._isRegistered$.next(false);
|
|
20997
21574
|
} catch (error) {
|
|
20998
|
-
logger$1.error("[SignalWire] Failed to unregister
|
|
21575
|
+
logger$1.error("[SignalWire] Failed to unregister user:", error);
|
|
20999
21576
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
21000
21577
|
throw error;
|
|
21001
21578
|
}
|
|
@@ -21135,6 +21712,36 @@ var SignalWire = class extends Destroyable {
|
|
|
21135
21712
|
selectAudioOutputDevice(device) {
|
|
21136
21713
|
this._deviceController.selectAudioOutputDevice(device);
|
|
21137
21714
|
}
|
|
21715
|
+
/**
|
|
21716
|
+
* Apply the currently selected audio output device to an HTMLMediaElement
|
|
21717
|
+
* (e.g. the `<audio>` or `<video>` element the consumer attached the
|
|
21718
|
+
* remote stream to). Uses `HTMLMediaElement.setSinkId` under the hood.
|
|
21719
|
+
* Returns a `Promise<boolean>`: `true` if the sink was applied,
|
|
21720
|
+
* `false` if the browser doesn't support `setSinkId` or no device is
|
|
21721
|
+
* selected.
|
|
21722
|
+
*
|
|
21723
|
+
* @example
|
|
21724
|
+
* ```ts
|
|
21725
|
+
* audioEl.srcObject = call.remoteStream;
|
|
21726
|
+
* await client.applySelectedAudioOutputDevice(audioEl);
|
|
21727
|
+
* ```
|
|
21728
|
+
*/
|
|
21729
|
+
async applySelectedAudioOutputDevice(element) {
|
|
21730
|
+
const device = this._deviceController.selectedAudioOutputDevice;
|
|
21731
|
+
if (!device?.deviceId) return false;
|
|
21732
|
+
const withSink = element;
|
|
21733
|
+
if (typeof withSink.setSinkId !== "function") {
|
|
21734
|
+
logger$1.warn("[SignalWire] setSinkId not supported on this element / browser");
|
|
21735
|
+
return false;
|
|
21736
|
+
}
|
|
21737
|
+
try {
|
|
21738
|
+
await withSink.setSinkId(device.deviceId);
|
|
21739
|
+
return true;
|
|
21740
|
+
} catch (error) {
|
|
21741
|
+
logger$1.warn("[SignalWire] Failed to apply audio output device:", error);
|
|
21742
|
+
return false;
|
|
21743
|
+
}
|
|
21744
|
+
}
|
|
21138
21745
|
/** Starts monitoring for media device changes (connect/disconnect). */
|
|
21139
21746
|
enableDeviceMonitoring() {
|
|
21140
21747
|
this._deviceController.enableDeviceMonitoring();
|
|
@@ -21315,6 +21922,7 @@ var EmbedTokenCredentialProvider = class {
|
|
|
21315
21922
|
try {
|
|
21316
21923
|
const response = await fetch(url, {
|
|
21317
21924
|
method: "POST",
|
|
21925
|
+
headers: { "Content-Type": "application/json" },
|
|
21318
21926
|
body: JSON.stringify({ token: this.embedToken }),
|
|
21319
21927
|
signal: controller.signal
|
|
21320
21928
|
});
|
|
@@ -21445,6 +22053,7 @@ exports.ClientPreferences = ClientPreferences;
|
|
|
21445
22053
|
exports.CollectionFetchError = CollectionFetchError;
|
|
21446
22054
|
exports.DPoPInitError = DPoPInitError;
|
|
21447
22055
|
exports.DeviceTokenError = DeviceTokenError;
|
|
22056
|
+
exports.EmbedTokenCredentialProvider = EmbedTokenCredentialProvider;
|
|
21448
22057
|
exports.InvalidCredentialsError = InvalidCredentialsError;
|
|
21449
22058
|
exports.MediaTrackError = MediaTrackError;
|
|
21450
22059
|
exports.MessageParseError = MessageParseError;
|
|
@@ -21456,12 +22065,13 @@ exports.SelfCapabilities = SelfCapabilities;
|
|
|
21456
22065
|
exports.SelfParticipant = SelfParticipant;
|
|
21457
22066
|
exports.SignalWire = SignalWire;
|
|
21458
22067
|
exports.StaticCredentialProvider = StaticCredentialProvider;
|
|
21459
|
-
exports.Subscriber = Subscriber;
|
|
21460
22068
|
exports.TokenRefreshError = TokenRefreshError;
|
|
21461
22069
|
exports.UnexpectedError = UnexpectedError;
|
|
22070
|
+
exports.User = User;
|
|
21462
22071
|
exports.VertoPongError = VertoPongError;
|
|
21463
22072
|
exports.WebRTCCall = WebRTCCall;
|
|
21464
22073
|
exports.embeddableCall = embeddableCall;
|
|
22074
|
+
exports.getLogger = getLogger;
|
|
21465
22075
|
exports.isSelfParticipant = isSelfParticipant;
|
|
21466
22076
|
exports.ready = ready;
|
|
21467
22077
|
exports.setDebugOptions = setDebugOptions;
|