@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.mjs
CHANGED
|
@@ -457,9 +457,9 @@ var require_Subscriber = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
457
457
|
var NotificationFactories_1 = require_NotificationFactories();
|
|
458
458
|
var timeoutProvider_1 = require_timeoutProvider();
|
|
459
459
|
var errorContext_1$2 = require_errorContext();
|
|
460
|
-
var Subscriber
|
|
461
|
-
__extends$16(Subscriber$
|
|
462
|
-
function Subscriber$
|
|
460
|
+
var Subscriber = function(_super) {
|
|
461
|
+
__extends$16(Subscriber$1, _super);
|
|
462
|
+
function Subscriber$1(destination) {
|
|
463
463
|
var _this = _super.call(this) || this;
|
|
464
464
|
_this.isStopped = false;
|
|
465
465
|
if (destination) {
|
|
@@ -468,54 +468,54 @@ var require_Subscriber = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
468
468
|
} else _this.destination = exports.EMPTY_OBSERVER;
|
|
469
469
|
return _this;
|
|
470
470
|
}
|
|
471
|
-
Subscriber$
|
|
471
|
+
Subscriber$1.create = function(next, error, complete) {
|
|
472
472
|
return new SafeSubscriber(next, error, complete);
|
|
473
473
|
};
|
|
474
|
-
Subscriber$
|
|
474
|
+
Subscriber$1.prototype.next = function(value) {
|
|
475
475
|
if (this.isStopped) handleStoppedNotification(NotificationFactories_1.nextNotification(value), this);
|
|
476
476
|
else this._next(value);
|
|
477
477
|
};
|
|
478
|
-
Subscriber$
|
|
478
|
+
Subscriber$1.prototype.error = function(err) {
|
|
479
479
|
if (this.isStopped) handleStoppedNotification(NotificationFactories_1.errorNotification(err), this);
|
|
480
480
|
else {
|
|
481
481
|
this.isStopped = true;
|
|
482
482
|
this._error(err);
|
|
483
483
|
}
|
|
484
484
|
};
|
|
485
|
-
Subscriber$
|
|
485
|
+
Subscriber$1.prototype.complete = function() {
|
|
486
486
|
if (this.isStopped) handleStoppedNotification(NotificationFactories_1.COMPLETE_NOTIFICATION, this);
|
|
487
487
|
else {
|
|
488
488
|
this.isStopped = true;
|
|
489
489
|
this._complete();
|
|
490
490
|
}
|
|
491
491
|
};
|
|
492
|
-
Subscriber$
|
|
492
|
+
Subscriber$1.prototype.unsubscribe = function() {
|
|
493
493
|
if (!this.closed) {
|
|
494
494
|
this.isStopped = true;
|
|
495
495
|
_super.prototype.unsubscribe.call(this);
|
|
496
496
|
this.destination = null;
|
|
497
497
|
}
|
|
498
498
|
};
|
|
499
|
-
Subscriber$
|
|
499
|
+
Subscriber$1.prototype._next = function(value) {
|
|
500
500
|
this.destination.next(value);
|
|
501
501
|
};
|
|
502
|
-
Subscriber$
|
|
502
|
+
Subscriber$1.prototype._error = function(err) {
|
|
503
503
|
try {
|
|
504
504
|
this.destination.error(err);
|
|
505
505
|
} finally {
|
|
506
506
|
this.unsubscribe();
|
|
507
507
|
}
|
|
508
508
|
};
|
|
509
|
-
Subscriber$
|
|
509
|
+
Subscriber$1.prototype._complete = function() {
|
|
510
510
|
try {
|
|
511
511
|
this.destination.complete();
|
|
512
512
|
} finally {
|
|
513
513
|
this.unsubscribe();
|
|
514
514
|
}
|
|
515
515
|
};
|
|
516
|
-
return Subscriber$
|
|
516
|
+
return Subscriber$1;
|
|
517
517
|
}(Subscription_1$10.Subscription);
|
|
518
|
-
exports.Subscriber = Subscriber
|
|
518
|
+
exports.Subscriber = Subscriber;
|
|
519
519
|
var _bind = Function.prototype.bind;
|
|
520
520
|
function bind(fn, thisArg) {
|
|
521
521
|
return _bind.call(fn, thisArg);
|
|
@@ -579,7 +579,7 @@ var require_Subscriber = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
579
579
|
return _this;
|
|
580
580
|
}
|
|
581
581
|
return SafeSubscriber$1;
|
|
582
|
-
}(Subscriber
|
|
582
|
+
}(Subscriber);
|
|
583
583
|
exports.SafeSubscriber = SafeSubscriber;
|
|
584
584
|
function handleUnhandledError(error) {
|
|
585
585
|
if (config_1$2.config.useDeprecatedSynchronousErrorHandling) errorContext_1$2.captureError(error);
|
|
@@ -1125,9 +1125,9 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1125
1125
|
var ObjectUnsubscribedError_1$1 = require_ObjectUnsubscribedError();
|
|
1126
1126
|
var arrRemove_1$6 = require_arrRemove();
|
|
1127
1127
|
var errorContext_1 = require_errorContext();
|
|
1128
|
-
var Subject$
|
|
1129
|
-
__extends$13(Subject$
|
|
1130
|
-
function Subject$
|
|
1128
|
+
var Subject$1 = function(_super) {
|
|
1129
|
+
__extends$13(Subject$2, _super);
|
|
1130
|
+
function Subject$2() {
|
|
1131
1131
|
var _this = _super.call(this) || this;
|
|
1132
1132
|
_this.closed = false;
|
|
1133
1133
|
_this.currentObservers = null;
|
|
@@ -1137,15 +1137,15 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1137
1137
|
_this.thrownError = null;
|
|
1138
1138
|
return _this;
|
|
1139
1139
|
}
|
|
1140
|
-
Subject$
|
|
1140
|
+
Subject$2.prototype.lift = function(operator) {
|
|
1141
1141
|
var subject = new AnonymousSubject(this, this);
|
|
1142
1142
|
subject.operator = operator;
|
|
1143
1143
|
return subject;
|
|
1144
1144
|
};
|
|
1145
|
-
Subject$
|
|
1145
|
+
Subject$2.prototype._throwIfClosed = function() {
|
|
1146
1146
|
if (this.closed) throw new ObjectUnsubscribedError_1$1.ObjectUnsubscribedError();
|
|
1147
1147
|
};
|
|
1148
|
-
Subject$
|
|
1148
|
+
Subject$2.prototype.next = function(value) {
|
|
1149
1149
|
var _this = this;
|
|
1150
1150
|
errorContext_1.errorContext(function() {
|
|
1151
1151
|
var e_1, _a;
|
|
@@ -1166,7 +1166,7 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1166
1166
|
}
|
|
1167
1167
|
});
|
|
1168
1168
|
};
|
|
1169
|
-
Subject$
|
|
1169
|
+
Subject$2.prototype.error = function(err) {
|
|
1170
1170
|
var _this = this;
|
|
1171
1171
|
errorContext_1.errorContext(function() {
|
|
1172
1172
|
_this._throwIfClosed();
|
|
@@ -1178,7 +1178,7 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1178
1178
|
}
|
|
1179
1179
|
});
|
|
1180
1180
|
};
|
|
1181
|
-
Subject$
|
|
1181
|
+
Subject$2.prototype.complete = function() {
|
|
1182
1182
|
var _this = this;
|
|
1183
1183
|
errorContext_1.errorContext(function() {
|
|
1184
1184
|
_this._throwIfClosed();
|
|
@@ -1189,11 +1189,11 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1189
1189
|
}
|
|
1190
1190
|
});
|
|
1191
1191
|
};
|
|
1192
|
-
Subject$
|
|
1192
|
+
Subject$2.prototype.unsubscribe = function() {
|
|
1193
1193
|
this.isStopped = this.closed = true;
|
|
1194
1194
|
this.observers = this.currentObservers = null;
|
|
1195
1195
|
};
|
|
1196
|
-
Object.defineProperty(Subject$
|
|
1196
|
+
Object.defineProperty(Subject$2.prototype, "observed", {
|
|
1197
1197
|
get: function() {
|
|
1198
1198
|
var _a;
|
|
1199
1199
|
return ((_a = this.observers) === null || _a === void 0 ? void 0 : _a.length) > 0;
|
|
@@ -1201,16 +1201,16 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1201
1201
|
enumerable: false,
|
|
1202
1202
|
configurable: true
|
|
1203
1203
|
});
|
|
1204
|
-
Subject$
|
|
1204
|
+
Subject$2.prototype._trySubscribe = function(subscriber) {
|
|
1205
1205
|
this._throwIfClosed();
|
|
1206
1206
|
return _super.prototype._trySubscribe.call(this, subscriber);
|
|
1207
1207
|
};
|
|
1208
|
-
Subject$
|
|
1208
|
+
Subject$2.prototype._subscribe = function(subscriber) {
|
|
1209
1209
|
this._throwIfClosed();
|
|
1210
1210
|
this._checkFinalizedStatuses(subscriber);
|
|
1211
1211
|
return this._innerSubscribe(subscriber);
|
|
1212
1212
|
};
|
|
1213
|
-
Subject$
|
|
1213
|
+
Subject$2.prototype._innerSubscribe = function(subscriber) {
|
|
1214
1214
|
var _this = this;
|
|
1215
1215
|
var _a = this, hasError = _a.hasError, isStopped = _a.isStopped, observers = _a.observers;
|
|
1216
1216
|
if (hasError || isStopped) return Subscription_1$6.EMPTY_SUBSCRIPTION;
|
|
@@ -1221,22 +1221,22 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1221
1221
|
arrRemove_1$6.arrRemove(observers, subscriber);
|
|
1222
1222
|
});
|
|
1223
1223
|
};
|
|
1224
|
-
Subject$
|
|
1224
|
+
Subject$2.prototype._checkFinalizedStatuses = function(subscriber) {
|
|
1225
1225
|
var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, isStopped = _a.isStopped;
|
|
1226
1226
|
if (hasError) subscriber.error(thrownError);
|
|
1227
1227
|
else if (isStopped) subscriber.complete();
|
|
1228
1228
|
};
|
|
1229
|
-
Subject$
|
|
1229
|
+
Subject$2.prototype.asObservable = function() {
|
|
1230
1230
|
var observable = new Observable_1$24.Observable();
|
|
1231
1231
|
observable.source = this;
|
|
1232
1232
|
return observable;
|
|
1233
1233
|
};
|
|
1234
|
-
Subject$
|
|
1234
|
+
Subject$2.create = function(destination, source) {
|
|
1235
1235
|
return new AnonymousSubject(destination, source);
|
|
1236
1236
|
};
|
|
1237
|
-
return Subject$
|
|
1237
|
+
return Subject$2;
|
|
1238
1238
|
}(Observable_1$24.Observable);
|
|
1239
|
-
exports.Subject = Subject$
|
|
1239
|
+
exports.Subject = Subject$1;
|
|
1240
1240
|
var AnonymousSubject = function(_super) {
|
|
1241
1241
|
__extends$13(AnonymousSubject$1, _super);
|
|
1242
1242
|
function AnonymousSubject$1(destination, source) {
|
|
@@ -1262,7 +1262,7 @@ var require_Subject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1262
1262
|
return (_b = (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber)) !== null && _b !== void 0 ? _b : Subscription_1$6.EMPTY_SUBSCRIPTION;
|
|
1263
1263
|
};
|
|
1264
1264
|
return AnonymousSubject$1;
|
|
1265
|
-
}(Subject$
|
|
1265
|
+
}(Subject$1);
|
|
1266
1266
|
exports.AnonymousSubject = AnonymousSubject;
|
|
1267
1267
|
}));
|
|
1268
1268
|
|
|
@@ -1289,37 +1289,37 @@ var require_BehaviorSubject = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1289
1289
|
})();
|
|
1290
1290
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1291
1291
|
exports.BehaviorSubject = void 0;
|
|
1292
|
-
var BehaviorSubject$
|
|
1293
|
-
__extends$12(BehaviorSubject$
|
|
1294
|
-
function BehaviorSubject$
|
|
1292
|
+
var BehaviorSubject$1 = function(_super) {
|
|
1293
|
+
__extends$12(BehaviorSubject$2, _super);
|
|
1294
|
+
function BehaviorSubject$2(_value) {
|
|
1295
1295
|
var _this = _super.call(this) || this;
|
|
1296
1296
|
_this._value = _value;
|
|
1297
1297
|
return _this;
|
|
1298
1298
|
}
|
|
1299
|
-
Object.defineProperty(BehaviorSubject$
|
|
1299
|
+
Object.defineProperty(BehaviorSubject$2.prototype, "value", {
|
|
1300
1300
|
get: function() {
|
|
1301
1301
|
return this.getValue();
|
|
1302
1302
|
},
|
|
1303
1303
|
enumerable: false,
|
|
1304
1304
|
configurable: true
|
|
1305
1305
|
});
|
|
1306
|
-
BehaviorSubject$
|
|
1306
|
+
BehaviorSubject$2.prototype._subscribe = function(subscriber) {
|
|
1307
1307
|
var subscription = _super.prototype._subscribe.call(this, subscriber);
|
|
1308
1308
|
!subscription.closed && subscriber.next(this._value);
|
|
1309
1309
|
return subscription;
|
|
1310
1310
|
};
|
|
1311
|
-
BehaviorSubject$
|
|
1311
|
+
BehaviorSubject$2.prototype.getValue = function() {
|
|
1312
1312
|
var _a = this, hasError = _a.hasError, thrownError = _a.thrownError, _value = _a._value;
|
|
1313
1313
|
if (hasError) throw thrownError;
|
|
1314
1314
|
this._throwIfClosed();
|
|
1315
1315
|
return _value;
|
|
1316
1316
|
};
|
|
1317
|
-
BehaviorSubject$
|
|
1317
|
+
BehaviorSubject$2.prototype.next = function(value) {
|
|
1318
1318
|
_super.prototype.next.call(this, this._value = value);
|
|
1319
1319
|
};
|
|
1320
|
-
return BehaviorSubject$
|
|
1320
|
+
return BehaviorSubject$2;
|
|
1321
1321
|
}(require_Subject().Subject);
|
|
1322
|
-
exports.BehaviorSubject = BehaviorSubject$
|
|
1322
|
+
exports.BehaviorSubject = BehaviorSubject$1;
|
|
1323
1323
|
}));
|
|
1324
1324
|
|
|
1325
1325
|
//#endregion
|
|
@@ -3091,13 +3091,13 @@ var require_of = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3091
3091
|
exports.of = void 0;
|
|
3092
3092
|
var args_1$12 = require_args();
|
|
3093
3093
|
var from_1$7 = require_from();
|
|
3094
|
-
function of$
|
|
3094
|
+
function of$2() {
|
|
3095
3095
|
var args = [];
|
|
3096
3096
|
for (var _i = 0; _i < arguments.length; _i++) args[_i] = arguments[_i];
|
|
3097
3097
|
var scheduler = args_1$12.popScheduler(args);
|
|
3098
3098
|
return from_1$7.from(args, scheduler);
|
|
3099
3099
|
}
|
|
3100
|
-
exports.of = of$
|
|
3100
|
+
exports.of = of$2;
|
|
3101
3101
|
}));
|
|
3102
3102
|
|
|
3103
3103
|
//#endregion
|
|
@@ -3246,7 +3246,7 @@ var require_firstValueFrom = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3246
3246
|
exports.firstValueFrom = void 0;
|
|
3247
3247
|
var EmptyError_1$5 = require_EmptyError();
|
|
3248
3248
|
var Subscriber_1$2 = require_Subscriber();
|
|
3249
|
-
function firstValueFrom$
|
|
3249
|
+
function firstValueFrom$7(source, config) {
|
|
3250
3250
|
var hasConfig = typeof config === "object";
|
|
3251
3251
|
return new Promise(function(resolve, reject) {
|
|
3252
3252
|
var subscriber = new Subscriber_1$2.SafeSubscriber({
|
|
@@ -3263,7 +3263,7 @@ var require_firstValueFrom = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3263
3263
|
source.subscribe(subscriber);
|
|
3264
3264
|
});
|
|
3265
3265
|
}
|
|
3266
|
-
exports.firstValueFrom = firstValueFrom$
|
|
3266
|
+
exports.firstValueFrom = firstValueFrom$7;
|
|
3267
3267
|
}));
|
|
3268
3268
|
|
|
3269
3269
|
//#endregion
|
|
@@ -3390,7 +3390,7 @@ var require_map = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3390
3390
|
exports.map = void 0;
|
|
3391
3391
|
var lift_1$64 = require_lift();
|
|
3392
3392
|
var OperatorSubscriber_1$54 = require_OperatorSubscriber();
|
|
3393
|
-
function map$
|
|
3393
|
+
function map$20(project, thisArg) {
|
|
3394
3394
|
return lift_1$64.operate(function(source, subscriber) {
|
|
3395
3395
|
var index = 0;
|
|
3396
3396
|
source.subscribe(OperatorSubscriber_1$54.createOperatorSubscriber(subscriber, function(value) {
|
|
@@ -3398,7 +3398,7 @@ var require_map = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3398
3398
|
}));
|
|
3399
3399
|
});
|
|
3400
3400
|
}
|
|
3401
|
-
exports.map = map$
|
|
3401
|
+
exports.map = map$20;
|
|
3402
3402
|
}));
|
|
3403
3403
|
|
|
3404
3404
|
//#endregion
|
|
@@ -4140,7 +4140,7 @@ var require_timer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
4140
4140
|
var async_1$11 = require_async();
|
|
4141
4141
|
var isScheduler_1 = require_isScheduler();
|
|
4142
4142
|
var isDate_1$1 = require_isDate();
|
|
4143
|
-
function timer$
|
|
4143
|
+
function timer$3(dueTime, intervalOrScheduler, scheduler) {
|
|
4144
4144
|
if (dueTime === void 0) dueTime = 0;
|
|
4145
4145
|
if (scheduler === void 0) scheduler = async_1$11.async;
|
|
4146
4146
|
var intervalDuration = -1;
|
|
@@ -4159,7 +4159,7 @@ var require_timer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
4159
4159
|
}, due);
|
|
4160
4160
|
});
|
|
4161
4161
|
}
|
|
4162
|
-
exports.timer = timer$
|
|
4162
|
+
exports.timer = timer$3;
|
|
4163
4163
|
}));
|
|
4164
4164
|
|
|
4165
4165
|
//#endregion
|
|
@@ -4169,13 +4169,13 @@ var require_interval = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
4169
4169
|
exports.interval = void 0;
|
|
4170
4170
|
var async_1$10 = require_async();
|
|
4171
4171
|
var timer_1$6 = require_timer();
|
|
4172
|
-
function interval$
|
|
4172
|
+
function interval$4(period, scheduler) {
|
|
4173
4173
|
if (period === void 0) period = 0;
|
|
4174
4174
|
if (scheduler === void 0) scheduler = async_1$10.asyncScheduler;
|
|
4175
4175
|
if (period < 0) period = 0;
|
|
4176
4176
|
return timer_1$6.timer(period, period, scheduler);
|
|
4177
4177
|
}
|
|
4178
|
-
exports.interval = interval$
|
|
4178
|
+
exports.interval = interval$4;
|
|
4179
4179
|
}));
|
|
4180
4180
|
|
|
4181
4181
|
//#endregion
|
|
@@ -4327,13 +4327,13 @@ var require_race$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
4327
4327
|
var innerFrom_1$28 = require_innerFrom();
|
|
4328
4328
|
var argsOrArgArray_1$4 = require_argsOrArgArray();
|
|
4329
4329
|
var OperatorSubscriber_1$48 = require_OperatorSubscriber();
|
|
4330
|
-
function race$
|
|
4330
|
+
function race$5() {
|
|
4331
4331
|
var sources = [];
|
|
4332
4332
|
for (var _i = 0; _i < arguments.length; _i++) sources[_i] = arguments[_i];
|
|
4333
4333
|
sources = argsOrArgArray_1$4.argsOrArgArray(sources);
|
|
4334
4334
|
return sources.length === 1 ? innerFrom_1$28.innerFrom(sources[0]) : new Observable_1$6.Observable(raceInit(sources));
|
|
4335
4335
|
}
|
|
4336
|
-
exports.race = race$
|
|
4336
|
+
exports.race = race$5;
|
|
4337
4337
|
function raceInit(sources) {
|
|
4338
4338
|
return function(subscriber) {
|
|
4339
4339
|
var subscriptions = [];
|
|
@@ -5331,7 +5331,7 @@ var require_take = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5331
5331
|
var empty_1$3 = require_empty();
|
|
5332
5332
|
var lift_1$46 = require_lift();
|
|
5333
5333
|
var OperatorSubscriber_1$35 = require_OperatorSubscriber();
|
|
5334
|
-
function take$
|
|
5334
|
+
function take$9(count$1) {
|
|
5335
5335
|
return count$1 <= 0 ? function() {
|
|
5336
5336
|
return empty_1$3.EMPTY;
|
|
5337
5337
|
} : lift_1$46.operate(function(source, subscriber) {
|
|
@@ -5344,7 +5344,7 @@ var require_take = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5344
5344
|
}));
|
|
5345
5345
|
});
|
|
5346
5346
|
}
|
|
5347
|
-
exports.take = take$
|
|
5347
|
+
exports.take = take$9;
|
|
5348
5348
|
}));
|
|
5349
5349
|
|
|
5350
5350
|
//#endregion
|
|
@@ -5470,7 +5470,7 @@ var require_distinctUntilChanged = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5470
5470
|
var identity_1$10 = require_identity();
|
|
5471
5471
|
var lift_1$42 = require_lift();
|
|
5472
5472
|
var OperatorSubscriber_1$31 = require_OperatorSubscriber();
|
|
5473
|
-
function distinctUntilChanged$
|
|
5473
|
+
function distinctUntilChanged$9(comparator, keySelector) {
|
|
5474
5474
|
if (keySelector === void 0) keySelector = identity_1$10.identity;
|
|
5475
5475
|
comparator = comparator !== null && comparator !== void 0 ? comparator : defaultCompare;
|
|
5476
5476
|
return lift_1$42.operate(function(source, subscriber) {
|
|
@@ -5486,7 +5486,7 @@ var require_distinctUntilChanged = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5486
5486
|
}));
|
|
5487
5487
|
});
|
|
5488
5488
|
}
|
|
5489
|
-
exports.distinctUntilChanged = distinctUntilChanged$
|
|
5489
|
+
exports.distinctUntilChanged = distinctUntilChanged$9;
|
|
5490
5490
|
function defaultCompare(a, b) {
|
|
5491
5491
|
return a === b;
|
|
5492
5492
|
}
|
|
@@ -7182,17 +7182,17 @@ var require_timeInterval = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7182
7182
|
var last$2 = scheduler.now();
|
|
7183
7183
|
source.subscribe(OperatorSubscriber_1$6.createOperatorSubscriber(subscriber, function(value) {
|
|
7184
7184
|
var now = scheduler.now();
|
|
7185
|
-
var interval$
|
|
7185
|
+
var interval$5 = now - last$2;
|
|
7186
7186
|
last$2 = now;
|
|
7187
|
-
subscriber.next(new TimeInterval(value, interval$
|
|
7187
|
+
subscriber.next(new TimeInterval(value, interval$5));
|
|
7188
7188
|
}));
|
|
7189
7189
|
});
|
|
7190
7190
|
}
|
|
7191
7191
|
exports.timeInterval = timeInterval;
|
|
7192
7192
|
var TimeInterval = function() {
|
|
7193
|
-
function TimeInterval$1(value, interval$
|
|
7193
|
+
function TimeInterval$1(value, interval$5) {
|
|
7194
7194
|
this.value = value;
|
|
7195
|
-
this.interval = interval$
|
|
7195
|
+
this.interval = interval$5;
|
|
7196
7196
|
}
|
|
7197
7197
|
return TimeInterval$1;
|
|
7198
7198
|
}();
|
|
@@ -8933,12 +8933,12 @@ var require_cjs = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
8933
8933
|
|
|
8934
8934
|
//#endregion
|
|
8935
8935
|
//#region src/behaviors/Destroyable.ts
|
|
8936
|
-
var import_cjs$
|
|
8936
|
+
var import_cjs$30 = require_cjs();
|
|
8937
8937
|
var Destroyable = class {
|
|
8938
8938
|
constructor() {
|
|
8939
8939
|
this.subscriptions = [];
|
|
8940
8940
|
this.subjects = [];
|
|
8941
|
-
this._destroyed$ = new import_cjs$
|
|
8941
|
+
this._destroyed$ = new import_cjs$30.Subject();
|
|
8942
8942
|
}
|
|
8943
8943
|
destroy() {
|
|
8944
8944
|
this._observableCache?.clear();
|
|
@@ -8974,7 +8974,7 @@ var Destroyable = class {
|
|
|
8974
8974
|
this._observableCache ??= /* @__PURE__ */ new Map();
|
|
8975
8975
|
let cached = this._observableCache.get(publicKey);
|
|
8976
8976
|
if (!cached) {
|
|
8977
|
-
cached = factory().pipe((0, import_cjs$
|
|
8977
|
+
cached = factory().pipe((0, import_cjs$30.observeOn)(import_cjs$30.asapScheduler));
|
|
8978
8978
|
this._observableCache.set(publicKey, cached);
|
|
8979
8979
|
}
|
|
8980
8980
|
return cached;
|
|
@@ -8988,24 +8988,24 @@ var Destroyable = class {
|
|
|
8988
8988
|
* Do NOT use for observables consumed internally by the SDK.
|
|
8989
8989
|
*/
|
|
8990
8990
|
deferEmission(observable) {
|
|
8991
|
-
return observable.pipe((0, import_cjs$
|
|
8991
|
+
return observable.pipe((0, import_cjs$30.observeOn)(import_cjs$30.asapScheduler));
|
|
8992
8992
|
}
|
|
8993
8993
|
subscribeTo(observable, observerOrNext) {
|
|
8994
8994
|
const subscription = observable.subscribe(observerOrNext);
|
|
8995
8995
|
this.subscriptions.push(subscription);
|
|
8996
8996
|
}
|
|
8997
8997
|
createSubject() {
|
|
8998
|
-
const subject = new import_cjs$
|
|
8998
|
+
const subject = new import_cjs$30.Subject();
|
|
8999
8999
|
this.subjects.push(subject);
|
|
9000
9000
|
return subject;
|
|
9001
9001
|
}
|
|
9002
9002
|
createReplaySubject(bufferSize, windowTime$1) {
|
|
9003
|
-
const subject = new import_cjs$
|
|
9003
|
+
const subject = new import_cjs$30.ReplaySubject(bufferSize, windowTime$1);
|
|
9004
9004
|
this.subjects.push(subject);
|
|
9005
9005
|
return subject;
|
|
9006
9006
|
}
|
|
9007
9007
|
createBehaviorSubject(initialValue) {
|
|
9008
|
-
const subject = new import_cjs$
|
|
9008
|
+
const subject = new import_cjs$30.BehaviorSubject(initialValue);
|
|
9009
9009
|
this.subjects.push(subject);
|
|
9010
9010
|
return subject;
|
|
9011
9011
|
}
|
|
@@ -9466,9 +9466,9 @@ var require_loglevel = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
9466
9466
|
defaultLogger$1 = new Logger();
|
|
9467
9467
|
defaultLogger$1.getLogger = function getLogger$1(name) {
|
|
9468
9468
|
if (typeof name !== "symbol" && typeof name !== "string" || name === "") throw new TypeError("You must supply a name when creating a logger.");
|
|
9469
|
-
var logger$
|
|
9470
|
-
if (!logger$
|
|
9471
|
-
return logger$
|
|
9469
|
+
var logger$32 = _loggersByName[name];
|
|
9470
|
+
if (!logger$32) logger$32 = _loggersByName[name] = new Logger(name, defaultLogger$1.methodFactory);
|
|
9471
|
+
return logger$32;
|
|
9472
9472
|
};
|
|
9473
9473
|
var _log = typeof window !== undefinedType ? window.log : void 0;
|
|
9474
9474
|
defaultLogger$1.noConflict = function() {
|
|
@@ -9504,8 +9504,8 @@ const defaultLoggerLevel = defaultLogger.levels.WARN;
|
|
|
9504
9504
|
defaultLogger.setLevel(defaultLoggerLevel);
|
|
9505
9505
|
let userLogger = null;
|
|
9506
9506
|
/** Replace the built-in logger with a custom implementation. Pass `null` to restore defaults. */
|
|
9507
|
-
const setLogger = (logger$
|
|
9508
|
-
userLogger = logger$
|
|
9507
|
+
const setLogger = (logger$32) => {
|
|
9508
|
+
userLogger = logger$32;
|
|
9509
9509
|
};
|
|
9510
9510
|
let debugOptions = {};
|
|
9511
9511
|
/** Configure debug options (e.g., `{ logWsTraffic: true }`). */
|
|
@@ -9544,13 +9544,13 @@ const wsTraffic = (options) => {
|
|
|
9544
9544
|
loggerInstance.debug(`[WebSocket] ${options.type.toUpperCase()}: non-JSON message`);
|
|
9545
9545
|
return;
|
|
9546
9546
|
}
|
|
9547
|
-
else payload = options
|
|
9547
|
+
else ({payload} = options);
|
|
9548
9548
|
const msg = shouldStringify(payload) ? JSON.stringify(payload, null, 2) : payload;
|
|
9549
9549
|
loggerInstance.debug(`${options.type.toUpperCase()}: \n`, msg, "\n");
|
|
9550
9550
|
};
|
|
9551
9551
|
const getLogger = () => {
|
|
9552
|
-
const logger$
|
|
9553
|
-
return new Proxy(logger$
|
|
9552
|
+
const logger$32 = getLoggerInstance();
|
|
9553
|
+
return new Proxy(logger$32, { get(_target, prop, _receiver) {
|
|
9554
9554
|
if (prop === "wsTraffic") return wsTraffic;
|
|
9555
9555
|
const instance = getLoggerInstance();
|
|
9556
9556
|
const value = Reflect.get(instance, prop);
|
|
@@ -9602,8 +9602,7 @@ const asyncRetry = async ({ asyncCallable, maxRetries: retries = DEFAULT_MAX_RET
|
|
|
9602
9602
|
|
|
9603
9603
|
//#endregion
|
|
9604
9604
|
//#region src/controllers/HTTPRequestController.ts
|
|
9605
|
-
|
|
9606
|
-
const logger$29 = getLogger();
|
|
9605
|
+
const logger$31 = getLogger();
|
|
9607
9606
|
const GET_PARAMS = {
|
|
9608
9607
|
method: "GET",
|
|
9609
9608
|
headers: { Accept: "application/json" }
|
|
@@ -9615,7 +9614,7 @@ const POST_PARAMS = {
|
|
|
9615
9614
|
"Content-Type": "application/json"
|
|
9616
9615
|
}
|
|
9617
9616
|
};
|
|
9618
|
-
var HTTPRequestController = class HTTPRequestController {
|
|
9617
|
+
var HTTPRequestController = class HTTPRequestController extends Destroyable {
|
|
9619
9618
|
static {
|
|
9620
9619
|
this.defaultMaxRetries = 3;
|
|
9621
9620
|
}
|
|
@@ -9636,11 +9635,12 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9636
9635
|
]);
|
|
9637
9636
|
}
|
|
9638
9637
|
constructor(baseURL, getCredential, options = {}) {
|
|
9638
|
+
super();
|
|
9639
9639
|
this.baseURL = baseURL;
|
|
9640
9640
|
this.getCredential = getCredential;
|
|
9641
|
-
this._responses$ =
|
|
9642
|
-
this._errors$ =
|
|
9643
|
-
this._status$ =
|
|
9641
|
+
this._responses$ = this.createSubject();
|
|
9642
|
+
this._errors$ = this.createSubject();
|
|
9643
|
+
this._status$ = this.createBehaviorSubject("idle");
|
|
9644
9644
|
this.maxRetries = options.maxRetries ?? HTTPRequestController.defaultMaxRetries;
|
|
9645
9645
|
this.retryDelayMin = options.retryDelayMin ?? HTTPRequestController.defaultRetryDelayMinMs;
|
|
9646
9646
|
this.retryDelayMax = options.retryDelayMax ?? HTTPRequestController.defaultRetryDelayMaxMs;
|
|
@@ -9666,7 +9666,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9666
9666
|
this._responses$.next(response);
|
|
9667
9667
|
return response;
|
|
9668
9668
|
} catch (error) {
|
|
9669
|
-
logger$
|
|
9669
|
+
logger$31.error("[HTTPRequestController] Request error:", error);
|
|
9670
9670
|
this._status$.next("error");
|
|
9671
9671
|
const err = error instanceof Error ? error : new Error("HTTP request failed", { cause: error });
|
|
9672
9672
|
this._errors$.next(err);
|
|
@@ -9693,7 +9693,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9693
9693
|
const url = this.buildURL(request.url);
|
|
9694
9694
|
const headers = this.buildHeaders(request.headers);
|
|
9695
9695
|
const timeout$5 = request.timeout ?? this.requestTimeout;
|
|
9696
|
-
logger$
|
|
9696
|
+
logger$31.debug("[HTTPRequestController] Executing request:", {
|
|
9697
9697
|
method: request.method,
|
|
9698
9698
|
url,
|
|
9699
9699
|
headers: Object.keys(headers).reduce((acc, key) => {
|
|
@@ -9713,7 +9713,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9713
9713
|
});
|
|
9714
9714
|
clearTimeout(timeoutId);
|
|
9715
9715
|
const httpResponse = await this.convertResponse(response);
|
|
9716
|
-
logger$
|
|
9716
|
+
logger$31.debug("[HTTPRequestController] Response received:", {
|
|
9717
9717
|
status: response.status,
|
|
9718
9718
|
statusText: response.statusText,
|
|
9719
9719
|
headers: [...response.headers.entries()],
|
|
@@ -9723,7 +9723,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9723
9723
|
} catch (error) {
|
|
9724
9724
|
clearTimeout(timeoutId);
|
|
9725
9725
|
if (error instanceof Error && error.name === "AbortError") throw new RequestTimeoutError(`Request timeout after ${timeout$5}ms`, { cause: error });
|
|
9726
|
-
logger$
|
|
9726
|
+
logger$31.error("[HTTPRequestController] Request failed:", error);
|
|
9727
9727
|
throw error;
|
|
9728
9728
|
}
|
|
9729
9729
|
}
|
|
@@ -9737,8 +9737,8 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
9737
9737
|
const credential = this.getCredential();
|
|
9738
9738
|
if (credential.token) {
|
|
9739
9739
|
headers.Authorization = `Bearer ${credential.token}`;
|
|
9740
|
-
logger$
|
|
9741
|
-
} else logger$
|
|
9740
|
+
logger$31.debug("[HTTPRequestController] Using Bearer token auth, token length:", credential.token.length);
|
|
9741
|
+
} else logger$31.warn("[HTTPRequestController] No credentials available for authentication");
|
|
9742
9742
|
return headers;
|
|
9743
9743
|
}
|
|
9744
9744
|
/**
|
|
@@ -9950,6 +9950,18 @@ const DEFAULT_ICE_DISCONNECTED_GRACE_PERIOD_MS = 3e3;
|
|
|
9950
9950
|
const DEFAULT_ICE_RESTART_TIMEOUT_MS$1 = 5e3;
|
|
9951
9951
|
/** Maximum recovery attempts before emitting 'max_attempts_reached'. */
|
|
9952
9952
|
const DEFAULT_MAX_RECOVERY_ATTEMPTS = 3;
|
|
9953
|
+
/** Upper bound in ms for waiting on iceGatheringState === 'complete' after an ICE restart. */
|
|
9954
|
+
const ICE_GATHERING_COMPLETE_TIMEOUT_MS = 1e4;
|
|
9955
|
+
/** Upper bound in ms for waiting on RTCPeerConnection.connectionState === 'connected' after a recovery ICE restart. */
|
|
9956
|
+
const PEER_CONNECTION_RECOVERY_WAIT_MS = 5e3;
|
|
9957
|
+
/** Polling interval in ms while waiting for RTCPeerConnection.connectionState to transition. */
|
|
9958
|
+
const PEER_CONNECTION_RECOVERY_POLL_MS = 100;
|
|
9959
|
+
/** Polling interval for LocalAudioPipeline.level$ (ms). ~30fps is smooth for meters. */
|
|
9960
|
+
const AUDIO_LEVEL_POLL_INTERVAL_MS = 33;
|
|
9961
|
+
/** RMS level threshold (0..1) above which the local participant is considered speaking. */
|
|
9962
|
+
const VAD_THRESHOLD = .03;
|
|
9963
|
+
/** Hold window in ms below the threshold before speaking$ flips back to false. */
|
|
9964
|
+
const VAD_HOLD_MS = 250;
|
|
9953
9965
|
/** Whether to persist device selections to storage by default. */
|
|
9954
9966
|
const DEFAULT_PERSIST_DEVICE_SELECTION = true;
|
|
9955
9967
|
/** Whether to auto-apply device changes to active calls by default. */
|
|
@@ -9998,7 +10010,7 @@ function fromMsToSec(milliseconds) {
|
|
|
9998
10010
|
|
|
9999
10011
|
//#endregion
|
|
10000
10012
|
//#region src/containers/PreferencesContainer.ts
|
|
10001
|
-
const logger$
|
|
10013
|
+
const logger$30 = getLogger();
|
|
10002
10014
|
var PreferencesContainer = class PreferencesContainer {
|
|
10003
10015
|
static get instance() {
|
|
10004
10016
|
this._instance ??= new PreferencesContainer();
|
|
@@ -10660,7 +10672,7 @@ var ClientPreferences = class {
|
|
|
10660
10672
|
if (!this._storage) return;
|
|
10661
10673
|
const data = collectStoredPreferences();
|
|
10662
10674
|
this._storage.setItem(PREFERENCES_STORAGE_KEY, data, "local").catch((error) => {
|
|
10663
|
-
logger$
|
|
10675
|
+
logger$30.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);
|
|
10664
10676
|
});
|
|
10665
10677
|
}
|
|
10666
10678
|
/** Loads preferences from storage and applies them to the container. */
|
|
@@ -10669,7 +10681,7 @@ var ClientPreferences = class {
|
|
|
10669
10681
|
this._storage.getItem(PREFERENCES_STORAGE_KEY, "local").then((stored) => {
|
|
10670
10682
|
if (stored) applyStoredPreferences(stored);
|
|
10671
10683
|
}).catch((error) => {
|
|
10672
|
-
logger$
|
|
10684
|
+
logger$30.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);
|
|
10673
10685
|
});
|
|
10674
10686
|
}
|
|
10675
10687
|
};
|
|
@@ -10690,8 +10702,8 @@ function toError(value) {
|
|
|
10690
10702
|
|
|
10691
10703
|
//#endregion
|
|
10692
10704
|
//#region src/controllers/NavigatorDeviceController.ts
|
|
10693
|
-
var import_cjs$
|
|
10694
|
-
const logger$
|
|
10705
|
+
var import_cjs$29 = require_cjs();
|
|
10706
|
+
const logger$29 = getLogger();
|
|
10695
10707
|
/** Maps a device kind to its storage key. */
|
|
10696
10708
|
const DEVICE_STORAGE_KEYS = {
|
|
10697
10709
|
audioinput: DEVICE_STORAGE_KEY_AUDIO_INPUT,
|
|
@@ -10713,7 +10725,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10713
10725
|
super();
|
|
10714
10726
|
this.webRTCApiProvider = webRTCApiProvider;
|
|
10715
10727
|
this.deviceChangeHandler = () => {
|
|
10716
|
-
logger$
|
|
10728
|
+
logger$29.debug("[DeviceController] Device change detected");
|
|
10717
10729
|
this.enumerateDevices();
|
|
10718
10730
|
};
|
|
10719
10731
|
this._devicesState$ = this.createBehaviorSubject(initialDevicesState);
|
|
@@ -10750,17 +10762,17 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10750
10762
|
return {};
|
|
10751
10763
|
}
|
|
10752
10764
|
get errors$() {
|
|
10753
|
-
return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$
|
|
10765
|
+
return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10754
10766
|
}
|
|
10755
10767
|
/** Observable that emits when the SDK auto-switches a device. */
|
|
10756
10768
|
get deviceRecovered$() {
|
|
10757
|
-
return this._deviceRecovered$.asObservable().pipe((0, import_cjs$
|
|
10769
|
+
return this._deviceRecovered$.asObservable().pipe((0, import_cjs$29.takeUntil)(this.destroyed$));
|
|
10758
10770
|
}
|
|
10759
10771
|
get videoInputDisabled$() {
|
|
10760
|
-
return this.cachedObservable("videoInputDisabled$", () => this._videoInputDisabled$.asObservable().pipe((0, import_cjs$
|
|
10772
|
+
return this.cachedObservable("videoInputDisabled$", () => this._videoInputDisabled$.asObservable().pipe((0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10761
10773
|
}
|
|
10762
10774
|
get audioInputDisabled$() {
|
|
10763
|
-
return this.cachedObservable("audioInputDisabled$", () => this._audioInputDisabled$.asObservable().pipe((0, import_cjs$
|
|
10775
|
+
return this.cachedObservable("audioInputDisabled$", () => this._audioInputDisabled$.asObservable().pipe((0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$)));
|
|
10764
10776
|
}
|
|
10765
10777
|
get videoInputDisabled() {
|
|
10766
10778
|
return this._videoInputDisabled$.value;
|
|
@@ -10769,22 +10781,22 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10769
10781
|
return this._audioInputDisabled$.value;
|
|
10770
10782
|
}
|
|
10771
10783
|
get audioInputDevices$() {
|
|
10772
|
-
return this.cachedObservable("audioInputDevices$", () => this._devicesState$.pipe((0, import_cjs$
|
|
10784
|
+
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$)));
|
|
10773
10785
|
}
|
|
10774
10786
|
get audioOutputDevices$() {
|
|
10775
|
-
return this.cachedObservable("audioOutputDevices$", () => this._devicesState$.pipe((0, import_cjs$
|
|
10787
|
+
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$)));
|
|
10776
10788
|
}
|
|
10777
10789
|
get videoInputDevices$() {
|
|
10778
|
-
return this.cachedObservable("videoInputDevices$", () => this._devicesState$.pipe((0, import_cjs$
|
|
10790
|
+
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$)));
|
|
10779
10791
|
}
|
|
10780
10792
|
get selectedAudioInputDevice$() {
|
|
10781
|
-
return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$
|
|
10793
|
+
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))));
|
|
10782
10794
|
}
|
|
10783
10795
|
get selectedAudioOutputDevice$() {
|
|
10784
|
-
return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$
|
|
10796
|
+
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))));
|
|
10785
10797
|
}
|
|
10786
10798
|
get selectedVideoInputDevice$() {
|
|
10787
|
-
return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$
|
|
10799
|
+
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))));
|
|
10788
10800
|
}
|
|
10789
10801
|
get selectedAudioInputDevice() {
|
|
10790
10802
|
if (this._audioInputDisabled$.value) return null;
|
|
@@ -10859,7 +10871,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10859
10871
|
if (device) this.persistDeviceSelection("audioinput", device);
|
|
10860
10872
|
}
|
|
10861
10873
|
selectVideoInputDevice(device) {
|
|
10862
|
-
logger$
|
|
10874
|
+
logger$29.debug("[DeviceController] Setting selected video input device:", device);
|
|
10863
10875
|
if (this._videoInputDisabled$.value && device) this._videoInputDisabled$.next(false);
|
|
10864
10876
|
const previous = this._selectedDevicesState$.value.videoinput;
|
|
10865
10877
|
if (previous && previous.deviceId !== device?.deviceId) this._deviceHistory.push("videoinput", previous);
|
|
@@ -10880,7 +10892,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10880
10892
|
}
|
|
10881
10893
|
init() {
|
|
10882
10894
|
this.loadPersistedDevices();
|
|
10883
|
-
this.subscribeTo(this._devicesState$.pipe((0, import_cjs$
|
|
10895
|
+
this.subscribeTo(this._devicesState$.pipe((0, import_cjs$29.debounceTime)(PreferencesContainer.instance.deviceDebounceTime)), (devicesState) => {
|
|
10884
10896
|
const currentSelected = this._selectedDevicesState$.value;
|
|
10885
10897
|
const newAudioInput = this._audioInputDisabled$.value ? null : this.resolveDevice("audioinput", devicesState.audioinput, currentSelected.audioinput, PreferencesContainer.instance.preferredAudioInput);
|
|
10886
10898
|
const newAudioOutput = this.resolveDevice("audiooutput", devicesState.audiooutput, currentSelected.audiooutput, PreferencesContainer.instance.preferredAudioOutput);
|
|
@@ -10916,7 +10928,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10916
10928
|
}
|
|
10917
10929
|
const fromHistory = this._deviceHistory.findInHistory(kind, devices);
|
|
10918
10930
|
if (fromHistory) {
|
|
10919
|
-
logger$
|
|
10931
|
+
logger$29.debug(`[DeviceController] Device disappeared, falling back to history: ${fromHistory.label}`);
|
|
10920
10932
|
this.emitDeviceRecovered(kind, selected, fromHistory, "device_disconnected");
|
|
10921
10933
|
return fromHistory;
|
|
10922
10934
|
}
|
|
@@ -10969,7 +10981,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10969
10981
|
try {
|
|
10970
10982
|
await this._storageManager.setItem(DEVICE_STORAGE_KEYS[kind], stored, "local");
|
|
10971
10983
|
} catch (error) {
|
|
10972
|
-
logger$
|
|
10984
|
+
logger$29.error(`[DeviceController] Failed to persist device selection for ${kind}:`, error);
|
|
10973
10985
|
}
|
|
10974
10986
|
}
|
|
10975
10987
|
async loadPersistedDevices() {
|
|
@@ -10985,7 +10997,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
10985
10997
|
[kind]: stored
|
|
10986
10998
|
};
|
|
10987
10999
|
} catch (error) {
|
|
10988
|
-
logger$
|
|
11000
|
+
logger$29.error(`[DeviceController] Failed to load persisted device for ${kind}:`, error);
|
|
10989
11001
|
}
|
|
10990
11002
|
}
|
|
10991
11003
|
/** Clears device history, persisted selections, and re-enumerates devices. */
|
|
@@ -11002,8 +11014,8 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
11002
11014
|
enableDeviceMonitoring() {
|
|
11003
11015
|
this.disableDeviceMonitoring();
|
|
11004
11016
|
this.webRTCApiProvider.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
|
|
11005
|
-
if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$
|
|
11006
|
-
logger$
|
|
11017
|
+
if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$29.interval)(PreferencesContainer.instance.devicePollingInterval).subscribe(() => {
|
|
11018
|
+
logger$29.debug("[DeviceController] Polling devices due to interval");
|
|
11007
11019
|
this.enumerateDevices();
|
|
11008
11020
|
});
|
|
11009
11021
|
this.enumerateDevices();
|
|
@@ -11029,13 +11041,13 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
11029
11041
|
videoinput: []
|
|
11030
11042
|
});
|
|
11031
11043
|
this._devicesState$.next(devicesByKind);
|
|
11032
|
-
logger$
|
|
11044
|
+
logger$29.debug("[DeviceController] Devices enumerated:", {
|
|
11033
11045
|
audioInputs: devicesByKind.audioinput.length,
|
|
11034
11046
|
audioOutputs: devicesByKind.audiooutput.length,
|
|
11035
11047
|
videoInputs: devicesByKind.videoinput.length
|
|
11036
11048
|
});
|
|
11037
11049
|
} catch (error) {
|
|
11038
|
-
logger$
|
|
11050
|
+
logger$29.error("[DeviceController] Failed to enumerate devices:", error);
|
|
11039
11051
|
this._errors$.next(toError(error));
|
|
11040
11052
|
}
|
|
11041
11053
|
}
|
|
@@ -11051,7 +11063,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
11051
11063
|
stream.getTracks().forEach((t) => t.stop());
|
|
11052
11064
|
return capabilities;
|
|
11053
11065
|
} catch (error) {
|
|
11054
|
-
logger$
|
|
11066
|
+
logger$29.error("[DeviceController] Failed to get device capabilities:", error);
|
|
11055
11067
|
this._errors$.next(toError(error));
|
|
11056
11068
|
throw error;
|
|
11057
11069
|
}
|
|
@@ -11203,15 +11215,15 @@ var DependencyContainer = class {
|
|
|
11203
11215
|
this._baseURL = this.apiHost;
|
|
11204
11216
|
this._credential = {};
|
|
11205
11217
|
}
|
|
11206
|
-
get
|
|
11207
|
-
return this.
|
|
11218
|
+
get userId() {
|
|
11219
|
+
return this.user.id;
|
|
11208
11220
|
}
|
|
11209
|
-
get
|
|
11210
|
-
if (!this.
|
|
11211
|
-
return this.
|
|
11221
|
+
get user() {
|
|
11222
|
+
if (!this._user) throw new DependencyError("User");
|
|
11223
|
+
return this._user;
|
|
11212
11224
|
}
|
|
11213
|
-
set
|
|
11214
|
-
this.
|
|
11225
|
+
set user(user) {
|
|
11226
|
+
this._user = user;
|
|
11215
11227
|
}
|
|
11216
11228
|
get storage() {
|
|
11217
11229
|
if (!this._storageManager) {
|
|
@@ -11257,16 +11269,16 @@ var DependencyContainer = class {
|
|
|
11257
11269
|
this._deviceController = void 0;
|
|
11258
11270
|
}
|
|
11259
11271
|
get authorizationStateKey() {
|
|
11260
|
-
return `sw:${this.
|
|
11272
|
+
return `sw:${this.userId}:as`;
|
|
11261
11273
|
}
|
|
11262
11274
|
get protocolKey() {
|
|
11263
|
-
return `sw:${this.
|
|
11275
|
+
return `sw:${this.userId}:pt`;
|
|
11264
11276
|
}
|
|
11265
11277
|
get attachedCallsKey() {
|
|
11266
|
-
return `sw:${this.
|
|
11278
|
+
return `sw:${this.userId}:att`;
|
|
11267
11279
|
}
|
|
11268
|
-
|
|
11269
|
-
return this.
|
|
11280
|
+
getUserFromAddressId() {
|
|
11281
|
+
return this.user.addresses[0]?.id ?? "";
|
|
11270
11282
|
}
|
|
11271
11283
|
set baseURL(baseURL) {
|
|
11272
11284
|
this._baseURL = baseURL;
|
|
@@ -11302,7 +11314,7 @@ var DependencyContainer = class {
|
|
|
11302
11314
|
|
|
11303
11315
|
//#endregion
|
|
11304
11316
|
//#region src/controllers/CryptoController.ts
|
|
11305
|
-
const logger$
|
|
11317
|
+
const logger$28 = getLogger();
|
|
11306
11318
|
const DPOP_DB_NAME = "sw-dpop";
|
|
11307
11319
|
const DPOP_DB_VERSION = 1;
|
|
11308
11320
|
const DPOP_STORE_NAME = "keys";
|
|
@@ -11361,7 +11373,7 @@ async function loadKeyPairFromDB() {
|
|
|
11361
11373
|
tx.oncomplete = () => db.close();
|
|
11362
11374
|
});
|
|
11363
11375
|
} catch (error) {
|
|
11364
|
-
logger$
|
|
11376
|
+
logger$28.warn("[DPoP] Failed to load key pair from IndexedDB:", error);
|
|
11365
11377
|
return null;
|
|
11366
11378
|
}
|
|
11367
11379
|
}
|
|
@@ -11381,7 +11393,7 @@ async function saveKeyPairToDB(keyPair) {
|
|
|
11381
11393
|
};
|
|
11382
11394
|
});
|
|
11383
11395
|
} catch (error) {
|
|
11384
|
-
logger$
|
|
11396
|
+
logger$28.warn("[DPoP] Failed to save key pair to IndexedDB:", error);
|
|
11385
11397
|
}
|
|
11386
11398
|
}
|
|
11387
11399
|
async function deleteKeyPairFromDB() {
|
|
@@ -11400,7 +11412,7 @@ async function deleteKeyPairFromDB() {
|
|
|
11400
11412
|
};
|
|
11401
11413
|
});
|
|
11402
11414
|
} catch (error) {
|
|
11403
|
-
logger$
|
|
11415
|
+
logger$28.warn("[DPoP] Failed to delete key pair from IndexedDB:", error);
|
|
11404
11416
|
}
|
|
11405
11417
|
}
|
|
11406
11418
|
/**
|
|
@@ -11460,13 +11472,13 @@ var CryptoController = class {
|
|
|
11460
11472
|
this._publicJwk = await crypto.subtle.exportKey("jwk", stored.publicKey);
|
|
11461
11473
|
this._fingerprint = await computeJwkThumbprint(this._publicJwk);
|
|
11462
11474
|
this._initialized = true;
|
|
11463
|
-
logger$
|
|
11475
|
+
logger$28.debug("[DPoP] Key pair restored from IndexedDB, fingerprint:", this._fingerprint);
|
|
11464
11476
|
return this._fingerprint;
|
|
11465
11477
|
} catch (error) {
|
|
11466
|
-
logger$
|
|
11478
|
+
logger$28.warn("[DPoP] Stored key pair unusable, generating new one:", error);
|
|
11467
11479
|
await deleteKeyPairFromDB();
|
|
11468
11480
|
}
|
|
11469
|
-
logger$
|
|
11481
|
+
logger$28.debug("[DPoP] Generating RSA key pair");
|
|
11470
11482
|
this._keyPair = await crypto.subtle.generateKey({
|
|
11471
11483
|
name: "RSASSA-PKCS1-v1_5",
|
|
11472
11484
|
modulusLength: 2048,
|
|
@@ -11481,7 +11493,7 @@ var CryptoController = class {
|
|
|
11481
11493
|
this._fingerprint = await computeJwkThumbprint(this._publicJwk);
|
|
11482
11494
|
this._initialized = true;
|
|
11483
11495
|
await saveKeyPairToDB(this._keyPair);
|
|
11484
|
-
logger$
|
|
11496
|
+
logger$28.debug("[DPoP] Key pair generated and persisted, fingerprint:", this._fingerprint);
|
|
11485
11497
|
return this._fingerprint;
|
|
11486
11498
|
}
|
|
11487
11499
|
/**
|
|
@@ -11547,7 +11559,7 @@ var CryptoController = class {
|
|
|
11547
11559
|
this._fingerprint = null;
|
|
11548
11560
|
this._initialized = false;
|
|
11549
11561
|
deleteKeyPairFromDB();
|
|
11550
|
-
logger$
|
|
11562
|
+
logger$28.debug("[DPoP] Controller destroyed");
|
|
11551
11563
|
}
|
|
11552
11564
|
get publicJwk() {
|
|
11553
11565
|
if (!this._publicJwk) throw new DPoPInitError("CryptoController not initialized. Call init() first.");
|
|
@@ -11570,8 +11582,8 @@ var CryptoController = class {
|
|
|
11570
11582
|
|
|
11571
11583
|
//#endregion
|
|
11572
11584
|
//#region src/controllers/NetworkMonitor.ts
|
|
11573
|
-
var import_cjs$
|
|
11574
|
-
const logger$
|
|
11585
|
+
var import_cjs$28 = require_cjs();
|
|
11586
|
+
const logger$27 = getLogger();
|
|
11575
11587
|
/**
|
|
11576
11588
|
* Safely check whether we are running in a browser environment
|
|
11577
11589
|
* with `window` and the relevant event targets.
|
|
@@ -11614,13 +11626,13 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11614
11626
|
this.attachListeners();
|
|
11615
11627
|
}
|
|
11616
11628
|
get isOnline$() {
|
|
11617
|
-
return this._isOnline$.asObservable().pipe((0, import_cjs$
|
|
11629
|
+
return this._isOnline$.asObservable().pipe((0, import_cjs$28.takeUntil)(this._destroyed$));
|
|
11618
11630
|
}
|
|
11619
11631
|
get isOnline() {
|
|
11620
11632
|
return this._isOnline$.value;
|
|
11621
11633
|
}
|
|
11622
11634
|
get networkChange$() {
|
|
11623
|
-
return this._networkChange$.asObservable().pipe((0, import_cjs$
|
|
11635
|
+
return this._networkChange$.asObservable().pipe((0, import_cjs$28.takeUntil)(this._destroyed$));
|
|
11624
11636
|
}
|
|
11625
11637
|
destroy() {
|
|
11626
11638
|
this.removeListeners();
|
|
@@ -11628,7 +11640,7 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11628
11640
|
}
|
|
11629
11641
|
attachListeners() {
|
|
11630
11642
|
if (!hasBrowserNetworkEvents()) {
|
|
11631
|
-
logger$
|
|
11643
|
+
logger$27.debug("NetworkMonitor: no browser environment detected, skipping event listeners");
|
|
11632
11644
|
return;
|
|
11633
11645
|
}
|
|
11634
11646
|
window.addEventListener("online", this._onOnline);
|
|
@@ -11636,7 +11648,7 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11636
11648
|
const connection = getNetworkConnection();
|
|
11637
11649
|
if (connection) connection.addEventListener("change", this._onConnectionChange);
|
|
11638
11650
|
this._listenersAttached = true;
|
|
11639
|
-
logger$
|
|
11651
|
+
logger$27.debug("NetworkMonitor: event listeners attached");
|
|
11640
11652
|
}
|
|
11641
11653
|
removeListeners() {
|
|
11642
11654
|
if (!this._listenersAttached) return;
|
|
@@ -11647,10 +11659,10 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11647
11659
|
if (connection) connection.removeEventListener("change", this._onConnectionChange);
|
|
11648
11660
|
}
|
|
11649
11661
|
this._listenersAttached = false;
|
|
11650
|
-
logger$
|
|
11662
|
+
logger$27.debug("NetworkMonitor: event listeners removed");
|
|
11651
11663
|
}
|
|
11652
11664
|
handleOnline() {
|
|
11653
|
-
logger$
|
|
11665
|
+
logger$27.info("NetworkMonitor: browser went online");
|
|
11654
11666
|
this._isOnline$.next(true);
|
|
11655
11667
|
this._networkChange$.next({
|
|
11656
11668
|
type: "online",
|
|
@@ -11659,7 +11671,7 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11659
11671
|
});
|
|
11660
11672
|
}
|
|
11661
11673
|
handleOffline() {
|
|
11662
|
-
logger$
|
|
11674
|
+
logger$27.info("NetworkMonitor: browser went offline");
|
|
11663
11675
|
this._isOnline$.next(false);
|
|
11664
11676
|
this._networkChange$.next({
|
|
11665
11677
|
type: "offline",
|
|
@@ -11668,7 +11680,7 @@ var NetworkMonitor = class extends Destroyable {
|
|
|
11668
11680
|
}
|
|
11669
11681
|
handleConnectionChange() {
|
|
11670
11682
|
const networkType = getNetworkType();
|
|
11671
|
-
logger$
|
|
11683
|
+
logger$27.info(`NetworkMonitor: connection changed — effectiveType=${networkType ?? "unknown"}`);
|
|
11672
11684
|
this._networkChange$.next({
|
|
11673
11685
|
type: "connection_change",
|
|
11674
11686
|
timestamp: Date.now(),
|
|
@@ -11783,8 +11795,8 @@ function getNavigatorMediaDevices() {
|
|
|
11783
11795
|
|
|
11784
11796
|
//#endregion
|
|
11785
11797
|
//#region src/controllers/PreflightRunner.ts
|
|
11786
|
-
var import_cjs$
|
|
11787
|
-
const logger$
|
|
11798
|
+
var import_cjs$27 = require_cjs();
|
|
11799
|
+
const logger$26 = getLogger();
|
|
11788
11800
|
const DEFAULT_MEDIA_TEST_DURATION_S = 10;
|
|
11789
11801
|
const ICE_GATHERING_TIMEOUT_MS = 1e4;
|
|
11790
11802
|
const SIGNALING_RTT_TIMEOUT_MS = 5e3;
|
|
@@ -11833,7 +11845,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11833
11845
|
if (!this._options.skipMediaTest) try {
|
|
11834
11846
|
bandwidth = await this.testMediaBandwidth(destination);
|
|
11835
11847
|
} catch (error) {
|
|
11836
|
-
logger$
|
|
11848
|
+
logger$26.warn("[PreflightRunner] Media bandwidth test failed:", error);
|
|
11837
11849
|
warnings.push("Media bandwidth test failed");
|
|
11838
11850
|
}
|
|
11839
11851
|
return {
|
|
@@ -11845,7 +11857,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11845
11857
|
warnings
|
|
11846
11858
|
};
|
|
11847
11859
|
} catch (error) {
|
|
11848
|
-
logger$
|
|
11860
|
+
logger$26.error("[PreflightRunner] Preflight test failed:", error);
|
|
11849
11861
|
throw new PreflightError("preflight", error instanceof Error ? error : new Error(String(error)));
|
|
11850
11862
|
} finally {
|
|
11851
11863
|
this.destroy();
|
|
@@ -11876,7 +11888,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11876
11888
|
if (track.kind === "video" && track.readyState === "live") videoWorking = true;
|
|
11877
11889
|
}
|
|
11878
11890
|
} catch (error) {
|
|
11879
|
-
logger$
|
|
11891
|
+
logger$26.warn("[PreflightRunner] Device test failed:", error);
|
|
11880
11892
|
} finally {
|
|
11881
11893
|
if (audioStream) audioStream.getTracks().forEach((t) => t.stop());
|
|
11882
11894
|
}
|
|
@@ -11903,7 +11915,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11903
11915
|
const candidateTypes = /* @__PURE__ */ new Set();
|
|
11904
11916
|
const startTime = Date.now();
|
|
11905
11917
|
const gatheringComplete = new Promise((resolve) => {
|
|
11906
|
-
const timer$
|
|
11918
|
+
const timer$4 = setTimeout(resolve, ICE_GATHERING_TIMEOUT_MS);
|
|
11907
11919
|
peerConnection.onicecandidate = (event) => {
|
|
11908
11920
|
if (event.candidate) {
|
|
11909
11921
|
const candidateStr = event.candidate.candidate;
|
|
@@ -11911,7 +11923,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11911
11923
|
if (candidateStr.includes("typ srflx")) candidateTypes.add("srflx");
|
|
11912
11924
|
if (candidateStr.includes("typ relay")) candidateTypes.add("relay");
|
|
11913
11925
|
} else {
|
|
11914
|
-
clearTimeout(timer$
|
|
11926
|
+
clearTimeout(timer$4);
|
|
11915
11927
|
resolve();
|
|
11916
11928
|
}
|
|
11917
11929
|
};
|
|
@@ -11934,7 +11946,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11934
11946
|
rttMs
|
|
11935
11947
|
};
|
|
11936
11948
|
} catch (error) {
|
|
11937
|
-
logger$
|
|
11949
|
+
logger$26.warn("[PreflightRunner] ICE connectivity test failed:", error);
|
|
11938
11950
|
return {
|
|
11939
11951
|
type: "failed",
|
|
11940
11952
|
turnReachable: false,
|
|
@@ -11952,7 +11964,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11952
11964
|
audio: true,
|
|
11953
11965
|
video: false
|
|
11954
11966
|
});
|
|
11955
|
-
await (0, import_cjs$
|
|
11967
|
+
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)));
|
|
11956
11968
|
const durationMs = this._options.duration * 1e3;
|
|
11957
11969
|
await new Promise((resolve) => setTimeout(resolve, durationMs));
|
|
11958
11970
|
const metrics = call.networkMetrics;
|
|
@@ -11981,8 +11993,8 @@ var PreflightRunner = class extends Destroyable {
|
|
|
11981
11993
|
|
|
11982
11994
|
//#endregion
|
|
11983
11995
|
//#region src/controllers/VisibilityController.ts
|
|
11984
|
-
var import_cjs$
|
|
11985
|
-
const logger$
|
|
11996
|
+
var import_cjs$26 = require_cjs();
|
|
11997
|
+
const logger$25 = getLogger();
|
|
11986
11998
|
/**
|
|
11987
11999
|
* Checks whether the document visibility API is available.
|
|
11988
12000
|
*/
|
|
@@ -12019,15 +12031,15 @@ var VisibilityController = class extends Destroyable {
|
|
|
12019
12031
|
this._boundHandler = this._handleVisibilityChange.bind(this);
|
|
12020
12032
|
if (this._hasVisibilityApi) {
|
|
12021
12033
|
document.addEventListener("visibilitychange", this._boundHandler);
|
|
12022
|
-
logger$
|
|
12023
|
-
} else logger$
|
|
12034
|
+
logger$25.debug("VisibilityController: listening for visibilitychange events");
|
|
12035
|
+
} else logger$25.debug("VisibilityController: document visibility API not available, defaulting to visible");
|
|
12024
12036
|
}
|
|
12025
12037
|
/**
|
|
12026
12038
|
* Observable of the current visibility state.
|
|
12027
12039
|
* Emits 'visible' or 'hidden'. Always starts with the current state.
|
|
12028
12040
|
*/
|
|
12029
12041
|
get visibility$() {
|
|
12030
|
-
return this._visibility$.pipe((0, import_cjs$
|
|
12042
|
+
return this._visibility$.pipe((0, import_cjs$26.takeUntil)(this._destroyed$));
|
|
12031
12043
|
}
|
|
12032
12044
|
/**
|
|
12033
12045
|
* The current visibility state value.
|
|
@@ -12040,12 +12052,12 @@ var VisibilityController = class extends Destroyable {
|
|
|
12040
12052
|
* Each event includes the previous state, new state, and timestamp.
|
|
12041
12053
|
*/
|
|
12042
12054
|
get visibilityChange$() {
|
|
12043
|
-
return this._visibilityChange$.pipe((0, import_cjs$
|
|
12055
|
+
return this._visibilityChange$.pipe((0, import_cjs$26.takeUntil)(this._destroyed$));
|
|
12044
12056
|
}
|
|
12045
12057
|
destroy() {
|
|
12046
12058
|
if (this._hasVisibilityApi) {
|
|
12047
12059
|
document.removeEventListener("visibilitychange", this._boundHandler);
|
|
12048
|
-
logger$
|
|
12060
|
+
logger$25.debug("VisibilityController: removed visibilitychange listener");
|
|
12049
12061
|
}
|
|
12050
12062
|
super.destroy();
|
|
12051
12063
|
}
|
|
@@ -12063,7 +12075,7 @@ var VisibilityController = class extends Destroyable {
|
|
|
12063
12075
|
timestamp: Date.now()
|
|
12064
12076
|
};
|
|
12065
12077
|
this._visibilityChange$.next(changeEvent);
|
|
12066
|
-
logger$
|
|
12078
|
+
logger$25.debug("VisibilityController: visibility changed", {
|
|
12067
12079
|
from: previousState,
|
|
12068
12080
|
to: newState
|
|
12069
12081
|
});
|
|
@@ -12072,13 +12084,13 @@ var VisibilityController = class extends Destroyable {
|
|
|
12072
12084
|
|
|
12073
12085
|
//#endregion
|
|
12074
12086
|
//#region src/behaviors/Fetchable.ts
|
|
12075
|
-
var import_cjs$
|
|
12087
|
+
var import_cjs$25 = require_cjs();
|
|
12076
12088
|
var Fetchable = class extends Destroyable {
|
|
12077
12089
|
constructor(fromPath, http) {
|
|
12078
12090
|
super();
|
|
12079
12091
|
this.fromPath = fromPath;
|
|
12080
12092
|
this.http = http;
|
|
12081
|
-
this.fetched$ = (0, import_cjs$
|
|
12093
|
+
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$));
|
|
12082
12094
|
}
|
|
12083
12095
|
async fetch() {
|
|
12084
12096
|
const response = await this.http.request({
|
|
@@ -12096,14 +12108,14 @@ var Fetchable = class extends Destroyable {
|
|
|
12096
12108
|
};
|
|
12097
12109
|
|
|
12098
12110
|
//#endregion
|
|
12099
|
-
//#region src/core/entities/
|
|
12111
|
+
//#region src/core/entities/User.ts
|
|
12100
12112
|
/**
|
|
12101
|
-
* Authenticated
|
|
12113
|
+
* Authenticated user profile.
|
|
12102
12114
|
*
|
|
12103
12115
|
* Fetched automatically when a {@link SignalWire} connects.
|
|
12104
12116
|
* Contains identity, contact, and organization details.
|
|
12105
12117
|
*/
|
|
12106
|
-
var
|
|
12118
|
+
var User = class extends Fetchable {
|
|
12107
12119
|
constructor(http) {
|
|
12108
12120
|
super("/api/fabric/subscriber/info", http);
|
|
12109
12121
|
}
|
|
@@ -12313,20 +12325,18 @@ const RPCEventAckResponse = (id) => makeRPCResponse({
|
|
|
12313
12325
|
|
|
12314
12326
|
//#endregion
|
|
12315
12327
|
//#region src/managers/AttachManager.ts
|
|
12316
|
-
const logger$
|
|
12328
|
+
const logger$24 = getLogger();
|
|
12317
12329
|
var AttachManager = class {
|
|
12318
12330
|
constructor(storage, deviceController, reconnectCallsTimeout, attachKey) {
|
|
12319
12331
|
this.storage = storage;
|
|
12320
12332
|
this.deviceController = deviceController;
|
|
12321
12333
|
this.reconnectCallsTimeout = reconnectCallsTimeout;
|
|
12322
12334
|
this.attachKey = attachKey;
|
|
12335
|
+
this.writeQueue = Promise.resolve();
|
|
12323
12336
|
}
|
|
12324
12337
|
async detachAll() {
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
id: callId,
|
|
12328
|
-
nodeId: attached[callId].nodeId,
|
|
12329
|
-
mediaDirections: attached[callId].mediaDirections
|
|
12338
|
+
await this.mutate((attached) => {
|
|
12339
|
+
return {};
|
|
12330
12340
|
});
|
|
12331
12341
|
}
|
|
12332
12342
|
setSession(session) {
|
|
@@ -12336,7 +12346,7 @@ var AttachManager = class {
|
|
|
12336
12346
|
try {
|
|
12337
12347
|
return await this.storage.getItem(this.attachKey) ?? {};
|
|
12338
12348
|
} catch (error) {
|
|
12339
|
-
logger$
|
|
12349
|
+
logger$24.warn("[AttachManager] Failed to retrieve attached calls from storage", error);
|
|
12340
12350
|
return {};
|
|
12341
12351
|
}
|
|
12342
12352
|
}
|
|
@@ -12344,34 +12354,50 @@ var AttachManager = class {
|
|
|
12344
12354
|
try {
|
|
12345
12355
|
await this.storage.setItem(this.attachKey, attached);
|
|
12346
12356
|
} catch (error) {
|
|
12347
|
-
logger$
|
|
12357
|
+
logger$24.warn("[AttachManager] Failed to write attached calls to storage", error);
|
|
12348
12358
|
}
|
|
12349
12359
|
}
|
|
12360
|
+
/**
|
|
12361
|
+
* Serialize a read-modify-write operation against the attached-calls
|
|
12362
|
+
* storage. The mutator receives the current state and returns the new
|
|
12363
|
+
* state. Concurrent calls queue behind the in-flight one so writes never
|
|
12364
|
+
* interleave.
|
|
12365
|
+
*/
|
|
12366
|
+
async mutate(mutator) {
|
|
12367
|
+
const next = this.writeQueue.then(async () => {
|
|
12368
|
+
const updated = await mutator(await this.readAttached());
|
|
12369
|
+
await this.writeAttached(updated);
|
|
12370
|
+
});
|
|
12371
|
+
this.writeQueue = next.catch(() => void 0);
|
|
12372
|
+
return next;
|
|
12373
|
+
}
|
|
12350
12374
|
async attach(call) {
|
|
12351
12375
|
if (!call.to) {
|
|
12352
|
-
logger$
|
|
12376
|
+
logger$24.warn("[AttachManager] Skip attach for calls with no destination");
|
|
12353
12377
|
return;
|
|
12354
12378
|
}
|
|
12379
|
+
const destination = call.to;
|
|
12355
12380
|
const attachment = {
|
|
12356
12381
|
nodeId: call.nodeId,
|
|
12357
|
-
destination
|
|
12382
|
+
destination,
|
|
12358
12383
|
mediaDirections: call.mediaDirections,
|
|
12359
12384
|
audioInputDevice: call.mediaDirections.audio !== "inactive" ? this.deviceController.selectedAudioInputDevice : null,
|
|
12360
12385
|
videoInputDevice: call.mediaDirections.video !== "inactive" ? this.deviceController.selectedVideoInputDevice : null,
|
|
12361
12386
|
attachedAt: Date.now()
|
|
12362
12387
|
};
|
|
12363
|
-
|
|
12364
|
-
...
|
|
12388
|
+
await this.mutate((attached) => ({
|
|
12389
|
+
...attached,
|
|
12365
12390
|
[call.id]: attachment
|
|
12366
|
-
};
|
|
12367
|
-
await this.writeAttached(updated);
|
|
12391
|
+
}));
|
|
12368
12392
|
}
|
|
12369
12393
|
async detach(call) {
|
|
12370
|
-
|
|
12371
|
-
|
|
12394
|
+
await this.mutate((attached) => {
|
|
12395
|
+
const { [call.id]: _, ...remaining } = attached;
|
|
12396
|
+
return remaining;
|
|
12397
|
+
});
|
|
12372
12398
|
}
|
|
12373
12399
|
async flush() {
|
|
12374
|
-
await this.
|
|
12400
|
+
await this.mutate(() => ({}));
|
|
12375
12401
|
}
|
|
12376
12402
|
/**
|
|
12377
12403
|
* Reattach to previously active calls by sending verto.invite with
|
|
@@ -12400,15 +12426,15 @@ var AttachManager = class {
|
|
|
12400
12426
|
callId,
|
|
12401
12427
|
...options
|
|
12402
12428
|
});
|
|
12403
|
-
logger$
|
|
12429
|
+
logger$24.info(`[AttachManager] Reattached call ${callId} (attempt ${attempt})`);
|
|
12404
12430
|
succeeded = true;
|
|
12405
12431
|
break;
|
|
12406
12432
|
} catch (error) {
|
|
12407
|
-
logger$
|
|
12433
|
+
logger$24.warn(`[AttachManager] Reattach attempt ${attempt}/3 failed for call ${callId}:`, error);
|
|
12408
12434
|
if (attempt < 3) await new Promise((r) => setTimeout(r, (attempt + 1) * 1e3));
|
|
12409
12435
|
}
|
|
12410
12436
|
if (!succeeded) {
|
|
12411
|
-
logger$
|
|
12437
|
+
logger$24.warn(`[AttachManager] Reattach failed after 3 attempts for call ${callId}, removing reference`);
|
|
12412
12438
|
await this.detach({
|
|
12413
12439
|
id: callId,
|
|
12414
12440
|
mediaDirections: attachment.mediaDirections
|
|
@@ -12443,20 +12469,31 @@ var AttachManager = class {
|
|
|
12443
12469
|
};
|
|
12444
12470
|
}
|
|
12445
12471
|
/**
|
|
12446
|
-
*
|
|
12447
|
-
*
|
|
12472
|
+
* Look up stored attachment data for a call id and return CallOptions
|
|
12473
|
+
* suitable for rehydrating a reattached call. Returns undefined when no
|
|
12474
|
+
* matching entry exists in storage.
|
|
12475
|
+
*
|
|
12476
|
+
* Used by the session-level verto.attach handler when the server pushes
|
|
12477
|
+
* an attach event for a call the client doesn't have an object for yet
|
|
12478
|
+
* (e.g. after a reload).
|
|
12448
12479
|
*/
|
|
12449
|
-
consumePendingAttachment(
|
|
12450
|
-
async detachExpired() {
|
|
12480
|
+
async consumePendingAttachment(callId) {
|
|
12451
12481
|
const attached = await this.readAttached();
|
|
12482
|
+
if (!Object.hasOwn(attached, callId)) return;
|
|
12483
|
+
return this.buildCallOptions(attached[callId]);
|
|
12484
|
+
}
|
|
12485
|
+
async detachExpired() {
|
|
12452
12486
|
const now = Date.now();
|
|
12453
12487
|
const timeout$5 = this.reconnectCallsTimeout;
|
|
12454
|
-
|
|
12455
|
-
if (expired.length > 0) {
|
|
12488
|
+
await this.mutate((attached) => {
|
|
12456
12489
|
const remaining = { ...attached };
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12490
|
+
let changed = false;
|
|
12491
|
+
for (const [callId, attachment] of Object.entries(attached)) if (now - attachment.attachedAt > timeout$5) {
|
|
12492
|
+
delete remaining[callId];
|
|
12493
|
+
changed = true;
|
|
12494
|
+
}
|
|
12495
|
+
return changed ? remaining : attached;
|
|
12496
|
+
});
|
|
12460
12497
|
}
|
|
12461
12498
|
};
|
|
12462
12499
|
|
|
@@ -12503,12 +12540,12 @@ var require_race = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
12503
12540
|
exports.race = void 0;
|
|
12504
12541
|
var argsOrArgArray_1 = require_argsOrArgArray();
|
|
12505
12542
|
var raceWith_1$1 = require_raceWith();
|
|
12506
|
-
function race$
|
|
12543
|
+
function race$4() {
|
|
12507
12544
|
var args = [];
|
|
12508
12545
|
for (var _i = 0; _i < arguments.length; _i++) args[_i] = arguments[_i];
|
|
12509
12546
|
return raceWith_1$1.raceWith.apply(void 0, __spreadArray([], __read(argsOrArgArray_1.argsOrArgArray(args))));
|
|
12510
12547
|
}
|
|
12511
|
-
exports.race = race$
|
|
12548
|
+
exports.race = race$4;
|
|
12512
12549
|
}));
|
|
12513
12550
|
|
|
12514
12551
|
//#endregion
|
|
@@ -13436,7 +13473,7 @@ function computeCapabilities(capabilities) {
|
|
|
13436
13473
|
|
|
13437
13474
|
//#endregion
|
|
13438
13475
|
//#region src/core/capabilities/SelfCapabilities.ts
|
|
13439
|
-
var import_cjs$
|
|
13476
|
+
var import_cjs$24 = require_cjs();
|
|
13440
13477
|
/**
|
|
13441
13478
|
* SelfCapabilities manages the capability state for the self participant.
|
|
13442
13479
|
*
|
|
@@ -13472,7 +13509,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13472
13509
|
}
|
|
13473
13510
|
/** Observable for self member capabilities */
|
|
13474
13511
|
get self$() {
|
|
13475
|
-
return this.cachedObservable("self$", () => this._state$.pipe((0, import_cjs$
|
|
13512
|
+
return this.cachedObservable("self$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.self), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13476
13513
|
}
|
|
13477
13514
|
/** Current self member capabilities */
|
|
13478
13515
|
get self() {
|
|
@@ -13480,7 +13517,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13480
13517
|
}
|
|
13481
13518
|
/** Observable for other member capabilities */
|
|
13482
13519
|
get member$() {
|
|
13483
|
-
return this.cachedObservable("member$", () => this._state$.pipe((0, import_cjs$
|
|
13520
|
+
return this.cachedObservable("member$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.member), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13484
13521
|
}
|
|
13485
13522
|
/** Current other member capabilities */
|
|
13486
13523
|
get member() {
|
|
@@ -13488,7 +13525,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13488
13525
|
}
|
|
13489
13526
|
/** Observable for end call capability */
|
|
13490
13527
|
get end$() {
|
|
13491
|
-
return this.cachedObservable("end$", () => this._state$.pipe((0, import_cjs$
|
|
13528
|
+
return this.cachedObservable("end$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.end), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13492
13529
|
}
|
|
13493
13530
|
/** Current end call capability */
|
|
13494
13531
|
get end() {
|
|
@@ -13496,7 +13533,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13496
13533
|
}
|
|
13497
13534
|
/** Observable for set layout capability */
|
|
13498
13535
|
get setLayout$() {
|
|
13499
|
-
return this.cachedObservable("setLayout$", () => this._state$.pipe((0, import_cjs$
|
|
13536
|
+
return this.cachedObservable("setLayout$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.setLayout), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13500
13537
|
}
|
|
13501
13538
|
/** Current set layout capability */
|
|
13502
13539
|
get setLayout() {
|
|
@@ -13504,7 +13541,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13504
13541
|
}
|
|
13505
13542
|
/** Observable for send digit capability */
|
|
13506
13543
|
get sendDigit$() {
|
|
13507
|
-
return this.cachedObservable("sendDigit$", () => this._state$.pipe((0, import_cjs$
|
|
13544
|
+
return this.cachedObservable("sendDigit$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.sendDigit), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13508
13545
|
}
|
|
13509
13546
|
/** Current send digit capability */
|
|
13510
13547
|
get sendDigit() {
|
|
@@ -13512,7 +13549,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13512
13549
|
}
|
|
13513
13550
|
/** Observable for vmuted hide capability */
|
|
13514
13551
|
get vmutedHide$() {
|
|
13515
|
-
return this.cachedObservable("vmutedHide$", () => this._state$.pipe((0, import_cjs$
|
|
13552
|
+
return this.cachedObservable("vmutedHide$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.vmutedHide), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13516
13553
|
}
|
|
13517
13554
|
/** Current vmuted hide capability */
|
|
13518
13555
|
get vmutedHide() {
|
|
@@ -13520,7 +13557,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13520
13557
|
}
|
|
13521
13558
|
/** Observable for lock capability */
|
|
13522
13559
|
get lock$() {
|
|
13523
|
-
return this.cachedObservable("lock$", () => this._state$.pipe((0, import_cjs$
|
|
13560
|
+
return this.cachedObservable("lock$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.lock), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13524
13561
|
}
|
|
13525
13562
|
/** Current lock capability */
|
|
13526
13563
|
get lock() {
|
|
@@ -13528,7 +13565,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13528
13565
|
}
|
|
13529
13566
|
/** Observable for device capability */
|
|
13530
13567
|
get device$() {
|
|
13531
|
-
return this.cachedObservable("device$", () => this._state$.pipe((0, import_cjs$
|
|
13568
|
+
return this.cachedObservable("device$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.device), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13532
13569
|
}
|
|
13533
13570
|
/** Current device capability */
|
|
13534
13571
|
get device() {
|
|
@@ -13536,7 +13573,7 @@ var SelfCapabilities = class extends Destroyable {
|
|
|
13536
13573
|
}
|
|
13537
13574
|
/** Observable for screenshare capability */
|
|
13538
13575
|
get screenshare$() {
|
|
13539
|
-
return this.cachedObservable("screenshare$", () => this._state$.pipe((0, import_cjs$
|
|
13576
|
+
return this.cachedObservable("screenshare$", () => this._state$.pipe((0, import_cjs$24.map)((state) => state.screenshare), (0, import_cjs$24.distinctUntilChanged)()));
|
|
13540
13577
|
}
|
|
13541
13578
|
/** Current screenshare capability */
|
|
13542
13579
|
get screenshare() {
|
|
@@ -13564,7 +13601,7 @@ function toggleHandraiseMethod(is) {
|
|
|
13564
13601
|
|
|
13565
13602
|
//#endregion
|
|
13566
13603
|
//#region src/core/entities/Participant.ts
|
|
13567
|
-
const logger$
|
|
13604
|
+
const logger$23 = getLogger();
|
|
13568
13605
|
const initialState = {};
|
|
13569
13606
|
/**
|
|
13570
13607
|
* Represents a participant in a call.
|
|
@@ -13616,15 +13653,35 @@ var Participant = class extends Destroyable {
|
|
|
13616
13653
|
get deaf$() {
|
|
13617
13654
|
return this.cachedObservable("deaf$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.deaf), (0, import_operators$1.distinctUntilChanged)()));
|
|
13618
13655
|
}
|
|
13619
|
-
/**
|
|
13656
|
+
/**
|
|
13657
|
+
* Observable of the participant's **server-side** microphone input volume
|
|
13658
|
+
* as reported by the mix engine. This is gain applied on the bridged audio
|
|
13659
|
+
* leg (FreeSWITCH channel read volume), NOT the local browser mic. For a
|
|
13660
|
+
* local PC mic control, see {@link Call.setLocalMicrophoneGain}.
|
|
13661
|
+
*
|
|
13662
|
+
* @see {@link setAudioInputVolume}
|
|
13663
|
+
*/
|
|
13620
13664
|
get inputVolume$() {
|
|
13621
13665
|
return this.cachedObservable("inputVolume$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.input_volume), (0, import_operators$1.distinctUntilChanged)()));
|
|
13622
13666
|
}
|
|
13623
|
-
/**
|
|
13667
|
+
/**
|
|
13668
|
+
* Observable of the participant's **server-side** speaker output volume as
|
|
13669
|
+
* reported by the mix engine (FreeSWITCH channel write volume). NOT the
|
|
13670
|
+
* local HTML `<audio>` element volume — set that on your own element.
|
|
13671
|
+
*
|
|
13672
|
+
* @see {@link setAudioOutputVolume}
|
|
13673
|
+
*/
|
|
13624
13674
|
get outputVolume$() {
|
|
13625
13675
|
return this.cachedObservable("outputVolume$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.output_volume), (0, import_operators$1.distinctUntilChanged)()));
|
|
13626
13676
|
}
|
|
13627
|
-
/**
|
|
13677
|
+
/**
|
|
13678
|
+
* Observable of the **conference-only** microphone energy/gate sensitivity
|
|
13679
|
+
* level for this member. Routes through the conferencing mix engine and has
|
|
13680
|
+
* no effect on 1:1 WebRTC calls. Populated from `member.updated` events for
|
|
13681
|
+
* conference members.
|
|
13682
|
+
*
|
|
13683
|
+
* @see {@link setAudioInputSensitivity}
|
|
13684
|
+
*/
|
|
13628
13685
|
get inputSensitivity$() {
|
|
13629
13686
|
return this.cachedObservable("inputSensitivity$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.input_sensitivity), (0, import_operators$1.distinctUntilChanged)()));
|
|
13630
13687
|
}
|
|
@@ -13652,9 +13709,9 @@ var Participant = class extends Destroyable {
|
|
|
13652
13709
|
get meta$() {
|
|
13653
13710
|
return this.cachedObservable("meta$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.meta), (0, import_operators$1.distinctUntilChanged)()));
|
|
13654
13711
|
}
|
|
13655
|
-
/** Observable of the participant's
|
|
13656
|
-
get
|
|
13657
|
-
return this.cachedObservable("
|
|
13712
|
+
/** Observable of the participant's user ID. */
|
|
13713
|
+
get userId$() {
|
|
13714
|
+
return this.cachedObservable("userId$", () => this._state$.pipe((0, import_operators$1.map)((state) => state.subscriber_id), (0, import_operators$1.distinctUntilChanged)()));
|
|
13658
13715
|
}
|
|
13659
13716
|
/** Observable of the participant's address ID. */
|
|
13660
13717
|
get addressId$() {
|
|
@@ -13712,15 +13769,25 @@ var Participant = class extends Destroyable {
|
|
|
13712
13769
|
get deaf() {
|
|
13713
13770
|
return this._state$.value.deaf ?? false;
|
|
13714
13771
|
}
|
|
13715
|
-
/**
|
|
13772
|
+
/**
|
|
13773
|
+
* Current **server-side** microphone input volume as reported by the mix
|
|
13774
|
+
* engine, or `undefined` if not set. Not the local PC mic — see
|
|
13775
|
+
* {@link Call.setLocalMicrophoneGain} for browser-side control.
|
|
13776
|
+
*/
|
|
13716
13777
|
get inputVolume() {
|
|
13717
13778
|
return this._state$.value.input_volume;
|
|
13718
13779
|
}
|
|
13719
|
-
/**
|
|
13780
|
+
/**
|
|
13781
|
+
* Current **server-side** speaker output volume from the mix engine, or
|
|
13782
|
+
* `undefined` if not set. Not the local `<audio>` element volume.
|
|
13783
|
+
*/
|
|
13720
13784
|
get outputVolume() {
|
|
13721
13785
|
return this._state$.value.output_volume;
|
|
13722
13786
|
}
|
|
13723
|
-
/**
|
|
13787
|
+
/**
|
|
13788
|
+
* Current **conference-only** microphone sensitivity/gate level, or
|
|
13789
|
+
* `undefined` if not set. Applies only to conference members.
|
|
13790
|
+
*/
|
|
13724
13791
|
get inputSensitivity() {
|
|
13725
13792
|
return this._state$.value.input_sensitivity;
|
|
13726
13793
|
}
|
|
@@ -13748,8 +13815,8 @@ var Participant = class extends Destroyable {
|
|
|
13748
13815
|
get meta() {
|
|
13749
13816
|
return this._state$.value.meta;
|
|
13750
13817
|
}
|
|
13751
|
-
/**
|
|
13752
|
-
get
|
|
13818
|
+
/** User ID of this participant, or `undefined` if not available. */
|
|
13819
|
+
get userId() {
|
|
13753
13820
|
return this._state$.value.subscriber_id;
|
|
13754
13821
|
}
|
|
13755
13822
|
/** Address ID of this participant, or `undefined` if not available. */
|
|
@@ -13824,19 +13891,44 @@ var Participant = class extends Destroyable {
|
|
|
13824
13891
|
async toggleLowbitrate() {
|
|
13825
13892
|
throw new UnimplementedError();
|
|
13826
13893
|
}
|
|
13827
|
-
/**
|
|
13894
|
+
/**
|
|
13895
|
+
* Adjusts the **conference-only** microphone energy gate / sensitivity level
|
|
13896
|
+
* for this member. Routes through the conferencing mix engine
|
|
13897
|
+
* (`signalwire.conferencing member.set_input_sensitivity`) and has no effect
|
|
13898
|
+
* on 1:1 WebRTC calls — for those, use browser audio constraints via
|
|
13899
|
+
* {@link Call.setNoiseSuppression} / {@link Call.setAutoGainControl}.
|
|
13900
|
+
*
|
|
13901
|
+
* This is **not** a local PC mic gain control; it only changes how the
|
|
13902
|
+
* server-side mixer decides to open the mic gate on this participant.
|
|
13903
|
+
*
|
|
13904
|
+
* @param value - Sensitivity level as understood by the conference engine
|
|
13905
|
+
* (integer, larger values are more sensitive).
|
|
13906
|
+
*/
|
|
13828
13907
|
async setAudioInputSensitivity(value) {
|
|
13829
13908
|
await this.executeMethod(this.id, "call.microphone.sensitivity.set", { sensitivity: value });
|
|
13830
13909
|
}
|
|
13831
13910
|
/**
|
|
13832
|
-
* Sets the microphone
|
|
13911
|
+
* Sets the **server-side** microphone volume on this participant's bridged
|
|
13912
|
+
* call leg. Applies a multiplier to the audio flowing through the mix
|
|
13913
|
+
* engine (FreeSWITCH channel read volume) — changes what other participants
|
|
13914
|
+
* hear, not what the local browser captures.
|
|
13915
|
+
*
|
|
13916
|
+
* For local PC mic gain, use {@link Call.setLocalMicrophoneGain} instead.
|
|
13917
|
+
*
|
|
13833
13918
|
* @param value - Volume level (0-100).
|
|
13834
13919
|
*/
|
|
13835
13920
|
async setAudioInputVolume(value) {
|
|
13836
13921
|
await this.executeMethod(this.id, "call.microphone.volume.set", { volume: value });
|
|
13837
13922
|
}
|
|
13838
13923
|
/**
|
|
13839
|
-
* Sets the speaker
|
|
13924
|
+
* Sets the **server-side** speaker volume on this participant's bridged call
|
|
13925
|
+
* leg (FreeSWITCH channel write volume) — what this participant hears from
|
|
13926
|
+
* the mix before it reaches their client.
|
|
13927
|
+
*
|
|
13928
|
+
* For local playback volume (the `<audio>` element the consumer attaches
|
|
13929
|
+
* `remoteStream` to), set `audioElement.volume` directly in the consumer's
|
|
13930
|
+
* code.
|
|
13931
|
+
*
|
|
13840
13932
|
* @param value - Volume level (0-100).
|
|
13841
13933
|
*/
|
|
13842
13934
|
async setAudioOutputVolume(value) {
|
|
@@ -13942,7 +14034,7 @@ var SelfParticipant = class extends Participant {
|
|
|
13942
14034
|
try {
|
|
13943
14035
|
await this.vertoManager.addScreenMedia();
|
|
13944
14036
|
} catch (error) {
|
|
13945
|
-
logger$
|
|
14037
|
+
logger$23.error("[Participant.startScreenShare] Screen share error:", error);
|
|
13946
14038
|
}
|
|
13947
14039
|
}
|
|
13948
14040
|
/** Observable of the current screen share status. */
|
|
@@ -13962,7 +14054,7 @@ var SelfParticipant = class extends Participant {
|
|
|
13962
14054
|
try {
|
|
13963
14055
|
await this.vertoManager.addInputDevice(options);
|
|
13964
14056
|
} catch (error) {
|
|
13965
|
-
logger$
|
|
14057
|
+
logger$23.error("[Participant.startScreenShare] Screen share error:", error);
|
|
13966
14058
|
}
|
|
13967
14059
|
}
|
|
13968
14060
|
/** Removes an additional media input device by ID. */
|
|
@@ -14024,7 +14116,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14024
14116
|
*/
|
|
14025
14117
|
exitStudioModeIfActive() {
|
|
14026
14118
|
if (this._studioAudio$.value) {
|
|
14027
|
-
logger$
|
|
14119
|
+
logger$23.debug("[SelfParticipant] Exiting studio audio mode due to individual flag toggle");
|
|
14028
14120
|
this._studioAudio$.next(false);
|
|
14029
14121
|
}
|
|
14030
14122
|
}
|
|
@@ -14048,7 +14140,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14048
14140
|
try {
|
|
14049
14141
|
await super.mute();
|
|
14050
14142
|
} catch (error) {
|
|
14051
|
-
logger$
|
|
14143
|
+
logger$23.warn("[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway", error);
|
|
14052
14144
|
} finally {
|
|
14053
14145
|
this.vertoManager.muteMainAudioInputDevice();
|
|
14054
14146
|
}
|
|
@@ -14058,7 +14150,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14058
14150
|
try {
|
|
14059
14151
|
await super.unmute();
|
|
14060
14152
|
} catch (error) {
|
|
14061
|
-
logger$
|
|
14153
|
+
logger$23.warn("[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway", error);
|
|
14062
14154
|
} finally {
|
|
14063
14155
|
await this.vertoManager.unmuteMainAudioInputDevice();
|
|
14064
14156
|
}
|
|
@@ -14068,7 +14160,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14068
14160
|
try {
|
|
14069
14161
|
await super.muteVideo();
|
|
14070
14162
|
} catch (error) {
|
|
14071
|
-
logger$
|
|
14163
|
+
logger$23.warn("[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway", error);
|
|
14072
14164
|
} finally {
|
|
14073
14165
|
this.vertoManager.muteMainVideoInputDevice();
|
|
14074
14166
|
}
|
|
@@ -14078,7 +14170,7 @@ var SelfParticipant = class extends Participant {
|
|
|
14078
14170
|
try {
|
|
14079
14171
|
await super.unmuteVideo();
|
|
14080
14172
|
} catch (error) {
|
|
14081
|
-
logger$
|
|
14173
|
+
logger$23.warn("[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway", error);
|
|
14082
14174
|
} finally {
|
|
14083
14175
|
await this.vertoManager.unmuteMainVideoInputDevice();
|
|
14084
14176
|
}
|
|
@@ -14172,7 +14264,7 @@ function isLayoutChangedPayload(value) {
|
|
|
14172
14264
|
|
|
14173
14265
|
//#endregion
|
|
14174
14266
|
//#region src/operators/filterNull.ts
|
|
14175
|
-
var import_cjs$
|
|
14267
|
+
var import_cjs$23 = require_cjs();
|
|
14176
14268
|
/**
|
|
14177
14269
|
* RxJS operator that filters out `null` and `undefined` values with type narrowing.
|
|
14178
14270
|
*
|
|
@@ -14184,7 +14276,7 @@ var import_cjs$21 = require_cjs();
|
|
|
14184
14276
|
* ```
|
|
14185
14277
|
*/
|
|
14186
14278
|
function filterNull() {
|
|
14187
|
-
return (0, import_cjs$
|
|
14279
|
+
return (0, import_cjs$23.filter)((value) => value != null);
|
|
14188
14280
|
}
|
|
14189
14281
|
|
|
14190
14282
|
//#endregion
|
|
@@ -14199,7 +14291,7 @@ const getValueFrom = (obj, path, defaultValue) => {
|
|
|
14199
14291
|
|
|
14200
14292
|
//#endregion
|
|
14201
14293
|
//#region src/operators/filterEventAs.ts
|
|
14202
|
-
var import_cjs$
|
|
14294
|
+
var import_cjs$22 = require_cjs();
|
|
14203
14295
|
var import_operators = require_operators();
|
|
14204
14296
|
/**
|
|
14205
14297
|
* RxJS operator that filters events based on a predicate and maps matching events.
|
|
@@ -14233,7 +14325,7 @@ var import_operators = require_operators();
|
|
|
14233
14325
|
* ```
|
|
14234
14326
|
*/
|
|
14235
14327
|
function ifIsMap(predicate, mapFn) {
|
|
14236
|
-
return (0, import_cjs$
|
|
14328
|
+
return (0, import_cjs$22.pipe)((0, import_operators.filter)(predicate), (0, import_operators.map)(mapFn));
|
|
14237
14329
|
}
|
|
14238
14330
|
/**
|
|
14239
14331
|
* Generic RxJS operator that filters events using a type guard and extracts a property.
|
|
@@ -14275,38 +14367,38 @@ function ifIsMap(predicate, mapFn) {
|
|
|
14275
14367
|
* ```
|
|
14276
14368
|
*/
|
|
14277
14369
|
function filterAs(predicate, resultPath) {
|
|
14278
|
-
return (0, import_cjs$
|
|
14370
|
+
return (0, import_cjs$22.pipe)(ifIsMap(predicate, (event) => {
|
|
14279
14371
|
return getValueFrom(event, resultPath);
|
|
14280
14372
|
}), (0, import_operators.filter)((value) => value !== void 0));
|
|
14281
14373
|
}
|
|
14282
14374
|
|
|
14283
14375
|
//#endregion
|
|
14284
14376
|
//#region src/operators/throwOnRPCError.ts
|
|
14285
|
-
var import_cjs$
|
|
14286
|
-
const logger$
|
|
14377
|
+
var import_cjs$21 = require_cjs();
|
|
14378
|
+
const logger$22 = getLogger();
|
|
14287
14379
|
/**
|
|
14288
14380
|
* RxJS operator that throws a {@link JSONRPCError} when the RPC response contains an error.
|
|
14289
14381
|
* Passes successful responses through unchanged.
|
|
14290
14382
|
*/
|
|
14291
14383
|
function throwOnRPCError() {
|
|
14292
|
-
return (0, import_cjs$
|
|
14384
|
+
return (0, import_cjs$21.map)((response) => {
|
|
14293
14385
|
if (response.error) {
|
|
14294
|
-
logger$
|
|
14386
|
+
logger$22.error("[throwOnRPCError] RPC error response:", {
|
|
14295
14387
|
code: response.error.code,
|
|
14296
14388
|
message: response.error.message,
|
|
14297
14389
|
data: response.error.data
|
|
14298
14390
|
});
|
|
14299
14391
|
throw new JSONRPCError(response.error.code, response.error.message, response.error.data);
|
|
14300
14392
|
}
|
|
14301
|
-
logger$
|
|
14393
|
+
logger$22.debug("[throwOnRPCError] RPC successful response:", response);
|
|
14302
14394
|
return response;
|
|
14303
14395
|
});
|
|
14304
14396
|
}
|
|
14305
14397
|
|
|
14306
14398
|
//#endregion
|
|
14307
14399
|
//#region src/managers/CallEventsManager.ts
|
|
14308
|
-
var import_cjs$
|
|
14309
|
-
const logger$
|
|
14400
|
+
var import_cjs$20 = require_cjs();
|
|
14401
|
+
const logger$21 = getLogger();
|
|
14310
14402
|
const initialSessionState = {};
|
|
14311
14403
|
/** @internal */
|
|
14312
14404
|
var CallEventsManager = class extends Destroyable {
|
|
@@ -14322,7 +14414,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14322
14414
|
this.initSubscriptions();
|
|
14323
14415
|
}
|
|
14324
14416
|
get participants$() {
|
|
14325
|
-
return this.cachedObservable("participants$", () => this._participants$.asObservable().pipe((0, import_cjs$
|
|
14417
|
+
return this.cachedObservable("participants$", () => this._participants$.asObservable().pipe((0, import_cjs$20.map)((participantsRecord) => Object.values(participantsRecord))));
|
|
14326
14418
|
}
|
|
14327
14419
|
get participants() {
|
|
14328
14420
|
return Object.values(this._participants$.value);
|
|
@@ -14340,40 +14432,40 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14340
14432
|
return this.callIds.has(callId);
|
|
14341
14433
|
}
|
|
14342
14434
|
get recording$() {
|
|
14343
|
-
return this.cachedObservable("recording$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14435
|
+
return this.cachedObservable("recording$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.recording), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14344
14436
|
}
|
|
14345
14437
|
get recordings$() {
|
|
14346
|
-
return this.cachedObservable("recordings$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14438
|
+
return this.cachedObservable("recordings$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.recordings), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14347
14439
|
}
|
|
14348
14440
|
get streaming$() {
|
|
14349
|
-
return this.cachedObservable("streaming$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14441
|
+
return this.cachedObservable("streaming$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.streaming), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14350
14442
|
}
|
|
14351
14443
|
get streams$() {
|
|
14352
|
-
return this.cachedObservable("streams$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14444
|
+
return this.cachedObservable("streams$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.streams), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14353
14445
|
}
|
|
14354
14446
|
get playbacks$() {
|
|
14355
|
-
return this.cachedObservable("playbacks$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14447
|
+
return this.cachedObservable("playbacks$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.playbacks), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14356
14448
|
}
|
|
14357
14449
|
get raiseHandPriority$() {
|
|
14358
|
-
return this.cachedObservable("raiseHandPriority$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14450
|
+
return this.cachedObservable("raiseHandPriority$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.prioritize_handraise), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14359
14451
|
}
|
|
14360
14452
|
get locked$() {
|
|
14361
|
-
return this.cachedObservable("locked$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14453
|
+
return this.cachedObservable("locked$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.locked), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14362
14454
|
}
|
|
14363
14455
|
get meta$() {
|
|
14364
|
-
return this.cachedObservable("meta$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14456
|
+
return this.cachedObservable("meta$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.meta), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14365
14457
|
}
|
|
14366
14458
|
get capabilities$() {
|
|
14367
|
-
return this.cachedObservable("capabilities$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14459
|
+
return this.cachedObservable("capabilities$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.capabilities), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14368
14460
|
}
|
|
14369
14461
|
get layout$() {
|
|
14370
|
-
return this.cachedObservable("layout$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14462
|
+
return this.cachedObservable("layout$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.layout_name), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14371
14463
|
}
|
|
14372
14464
|
get layouts$() {
|
|
14373
|
-
return this.cachedObservable("layouts$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14465
|
+
return this.cachedObservable("layouts$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.layouts), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14374
14466
|
}
|
|
14375
14467
|
get layoutLayers$() {
|
|
14376
|
-
return this.cachedObservable("layoutLayers$", () => this._sessionState$.pipe((0, import_cjs$
|
|
14468
|
+
return this.cachedObservable("layoutLayers$", () => this._sessionState$.pipe((0, import_cjs$20.map)((state) => state.layout_layers), (0, import_cjs$20.distinctUntilChanged)(), filterNull()));
|
|
14377
14469
|
}
|
|
14378
14470
|
get self() {
|
|
14379
14471
|
return this._self$.value;
|
|
@@ -14410,7 +14502,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14410
14502
|
}
|
|
14411
14503
|
initSubscriptions() {
|
|
14412
14504
|
this.subscribeTo(this.callJoinedEvent$, (callJoinedEvent) => {
|
|
14413
|
-
logger$
|
|
14505
|
+
logger$21.debug("[CallEventsManager] Handling call.joined event for call/session IDs:", {
|
|
14414
14506
|
callId: callJoinedEvent.call_id,
|
|
14415
14507
|
roomSessionId: callJoinedEvent.room_session_id
|
|
14416
14508
|
});
|
|
@@ -14437,19 +14529,19 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14437
14529
|
if (this._self$.value?.capabilities.setLayout) this.updateLayouts();
|
|
14438
14530
|
});
|
|
14439
14531
|
this.subscribeTo(this.memberUpdates$, (member) => {
|
|
14440
|
-
logger$
|
|
14532
|
+
logger$21.debug("[CallEventsManager] Handling member update event for member ID:", member);
|
|
14441
14533
|
this.upsertParticipant(member);
|
|
14442
14534
|
});
|
|
14443
14535
|
this.subscribeTo(this.webRtcCallSession.memberLeft$, (memberLeftEvent) => {
|
|
14444
|
-
logger$
|
|
14536
|
+
logger$21.debug("[CallEventsManager] Handling member.left event for member ID:", memberLeftEvent.member.member_id);
|
|
14445
14537
|
const participants = { ...this._participants$.value };
|
|
14446
14538
|
if (memberLeftEvent.member.member_id in participants) {
|
|
14447
14539
|
delete participants[memberLeftEvent.member.member_id];
|
|
14448
14540
|
this._participants$.next(participants);
|
|
14449
|
-
} else logger$
|
|
14541
|
+
} else logger$21.warn(`[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`);
|
|
14450
14542
|
});
|
|
14451
14543
|
this.subscribeTo(this.webRtcCallSession.callUpdated$, (callUpdatedEvent) => {
|
|
14452
|
-
logger$
|
|
14544
|
+
logger$21.debug("[CallEventsManager] Handling call.updated event:", callUpdatedEvent);
|
|
14453
14545
|
const roomSession = callUpdatedEvent.room_session;
|
|
14454
14546
|
this._sessionState$.next({
|
|
14455
14547
|
...this._sessionState$.value,
|
|
@@ -14464,7 +14556,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14464
14556
|
});
|
|
14465
14557
|
});
|
|
14466
14558
|
this.subscribeTo(this.layoutChangedEvent$, (layoutChangedEvent) => {
|
|
14467
|
-
logger$
|
|
14559
|
+
logger$21.debug("[CallEventsManager] Handling layout.changed event:", layoutChangedEvent);
|
|
14468
14560
|
this._sessionState$.next({
|
|
14469
14561
|
...this._sessionState$.value,
|
|
14470
14562
|
layout_name: layoutChangedEvent.id,
|
|
@@ -14474,10 +14566,10 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14474
14566
|
});
|
|
14475
14567
|
}
|
|
14476
14568
|
updateParticipantPositions(layoutChangedEvent) {
|
|
14477
|
-
if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$
|
|
14569
|
+
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.");
|
|
14478
14570
|
layoutChangedEvent.layers.filter((layer) => !!layer.member_id).filter((layer) => {
|
|
14479
14571
|
if (!(layer.member_id in this._participants$.value)) {
|
|
14480
|
-
logger$
|
|
14572
|
+
logger$21.warn(`[CallEventsManager] Skipping layout layer for unknown member_id: ${layer.member_id}`);
|
|
14481
14573
|
return false;
|
|
14482
14574
|
}
|
|
14483
14575
|
return true;
|
|
@@ -14500,7 +14592,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14500
14592
|
layouts: response.result.layouts
|
|
14501
14593
|
});
|
|
14502
14594
|
}).catch((error) => {
|
|
14503
|
-
logger$
|
|
14595
|
+
logger$21.error("[CallEventsManager] Error fetching layouts:", error);
|
|
14504
14596
|
});
|
|
14505
14597
|
}
|
|
14506
14598
|
updateParticipants(members) {
|
|
@@ -14516,7 +14608,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14516
14608
|
}
|
|
14517
14609
|
const participant = this._participants$.value[member.member_id];
|
|
14518
14610
|
const oldValue = participant.value;
|
|
14519
|
-
logger$
|
|
14611
|
+
logger$21.debug("[CallEventsManager] Updating participant:", member.member_id, {
|
|
14520
14612
|
oldValue,
|
|
14521
14613
|
newValue: member
|
|
14522
14614
|
});
|
|
@@ -14528,18 +14620,18 @@ var CallEventsManager = class extends Destroyable {
|
|
|
14528
14620
|
this._participants$.next(this._participants$.value);
|
|
14529
14621
|
}
|
|
14530
14622
|
get callJoinedEvent$() {
|
|
14531
|
-
return this.cachedObservable("callJoinedEvent$", () => this.webRtcCallSession.callEvent$.pipe((0, import_cjs$
|
|
14532
|
-
logger$
|
|
14623
|
+
return this.cachedObservable("callJoinedEvent$", () => this.webRtcCallSession.callEvent$.pipe((0, import_cjs$20.filter)(isCallJoinedPayload), (0, import_cjs$20.tap)((event) => {
|
|
14624
|
+
logger$21.debug("[CallEventsManager] Call joined event:", event);
|
|
14533
14625
|
})));
|
|
14534
14626
|
}
|
|
14535
14627
|
get layoutChangedEvent$() {
|
|
14536
|
-
return this.cachedObservable("layoutChangedEvent$", () => this.webRtcCallSession.callEvent$.pipe(filterAs(isLayoutChangedPayload, "layout"), (0, import_cjs$
|
|
14537
|
-
logger$
|
|
14628
|
+
return this.cachedObservable("layoutChangedEvent$", () => this.webRtcCallSession.callEvent$.pipe(filterAs(isLayoutChangedPayload, "layout"), (0, import_cjs$20.tap)((event) => {
|
|
14629
|
+
logger$21.debug("[CallEventsManager] Layout changed event:", event);
|
|
14538
14630
|
})));
|
|
14539
14631
|
}
|
|
14540
14632
|
get memberUpdates$() {
|
|
14541
|
-
return this.cachedObservable("memberUpdates$", () => (0, import_cjs$
|
|
14542
|
-
logger$
|
|
14633
|
+
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) => {
|
|
14634
|
+
logger$21.debug("[CallEventsManager] Member update event:", event);
|
|
14543
14635
|
})));
|
|
14544
14636
|
}
|
|
14545
14637
|
destroy() {
|
|
@@ -14795,8 +14887,8 @@ function appendStereoParams(fmtpLine, maxBitrate) {
|
|
|
14795
14887
|
|
|
14796
14888
|
//#endregion
|
|
14797
14889
|
//#region src/controllers/ICEGatheringController.ts
|
|
14798
|
-
var import_cjs$
|
|
14799
|
-
const logger$
|
|
14890
|
+
var import_cjs$19 = require_cjs();
|
|
14891
|
+
const logger$20 = getLogger();
|
|
14800
14892
|
var ICEGatheringController = class extends Destroyable {
|
|
14801
14893
|
constructor(peerConnection, peerConnectionControllerNegotiating$, options = {}) {
|
|
14802
14894
|
super();
|
|
@@ -14804,23 +14896,23 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14804
14896
|
this.peerConnectionControllerNegotiating$ = peerConnectionControllerNegotiating$;
|
|
14805
14897
|
this.onicegatheringstatechangeHandler = () => {
|
|
14806
14898
|
const { iceGatheringState } = this.peerConnection;
|
|
14807
|
-
logger$
|
|
14899
|
+
logger$20.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);
|
|
14808
14900
|
if (iceGatheringState === "gathering") this._iceCandidatesState.next({
|
|
14809
14901
|
state: "gathering",
|
|
14810
14902
|
validSDP: false
|
|
14811
14903
|
});
|
|
14812
14904
|
};
|
|
14813
14905
|
this.onicecandidateHandler = (event) => {
|
|
14814
|
-
logger$
|
|
14906
|
+
logger$20.debug("[ICEGatheringController] ICE candidate event received:", event.candidate);
|
|
14815
14907
|
this.removeTimer("iceCandidateTimer");
|
|
14816
14908
|
if (event.candidate) this.iceCandidateTimer = setTimeout(() => {
|
|
14817
14909
|
if (this.peerConnection.iceGatheringState !== "complete") {
|
|
14818
|
-
logger$
|
|
14910
|
+
logger$20.warn("[ICEGatheringController] ICE candidate timeout, using current SDP");
|
|
14819
14911
|
this.handleICECandidateTimeout();
|
|
14820
14912
|
}
|
|
14821
14913
|
}, this.iceCandidateTimeout);
|
|
14822
14914
|
else {
|
|
14823
|
-
logger$
|
|
14915
|
+
logger$20.debug("[ICEGatheringController] ICE gathering completed: null candidate received");
|
|
14824
14916
|
this.removeTimer("iceGatheringTimer");
|
|
14825
14917
|
this.handleICEGatheringComplete();
|
|
14826
14918
|
}
|
|
@@ -14833,12 +14925,12 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14833
14925
|
this.iceGatheringTimeout = options.iceGatheringTimeout ?? DEFAULT_ICE_GATHERING_TIMEOUT_MS;
|
|
14834
14926
|
this.relayOnly = options.relayOnly ?? false;
|
|
14835
14927
|
this.setupEventListeners();
|
|
14836
|
-
this.subscribeTo(this.peerConnectionControllerNegotiating$.pipe((0, import_cjs$
|
|
14928
|
+
this.subscribeTo(this.peerConnectionControllerNegotiating$.pipe((0, import_cjs$19.filter)((isNegotiating) => isNegotiating)), (isNegotiating) => {
|
|
14837
14929
|
if (isNegotiating) {
|
|
14838
14930
|
this.setupEventListeners();
|
|
14839
14931
|
this.iceGatheringTimer = setTimeout(() => {
|
|
14840
14932
|
if (this.peerConnection.iceGatheringState !== "complete") {
|
|
14841
|
-
logger$
|
|
14933
|
+
logger$20.warn("[ICEGatheringController] ICE gathering timeout, using current SDP");
|
|
14842
14934
|
this.handleICEGatheringTimeout();
|
|
14843
14935
|
}
|
|
14844
14936
|
}, this.iceGatheringTimeout);
|
|
@@ -14852,7 +14944,7 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14852
14944
|
this.peerConnection.addEventListener("icegatheringstatechange", this.onicegatheringstatechangeHandler);
|
|
14853
14945
|
}
|
|
14854
14946
|
get iceCandidatesState$() {
|
|
14855
|
-
return this._iceCandidatesState.pipe((0, import_cjs$
|
|
14947
|
+
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));
|
|
14856
14948
|
}
|
|
14857
14949
|
get hasValidLocalDescriptionSDP() {
|
|
14858
14950
|
const sdp = this.peerConnection.localDescription?.sdp;
|
|
@@ -14865,9 +14957,9 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14865
14957
|
this.relayOnly = value;
|
|
14866
14958
|
}
|
|
14867
14959
|
handleICEGatheringComplete() {
|
|
14868
|
-
logger$
|
|
14869
|
-
logger$
|
|
14870
|
-
logger$
|
|
14960
|
+
logger$20.debug("[ICEGatheringController] Handling ICE gathering complete");
|
|
14961
|
+
logger$20.debug(`[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`);
|
|
14962
|
+
logger$20.debug("[ICEGatheringController] ICE gathering complete");
|
|
14871
14963
|
this._iceCandidatesState.next({
|
|
14872
14964
|
state: "complete",
|
|
14873
14965
|
validSDP: this.hasValidLocalDescriptionSDP
|
|
@@ -14883,21 +14975,21 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14883
14975
|
this.removeTimer("iceGatheringTimer");
|
|
14884
14976
|
const validSDP = this.hasValidLocalDescriptionSDP;
|
|
14885
14977
|
if (validSDP) {
|
|
14886
|
-
logger$
|
|
14978
|
+
logger$20.debug("[ICEGatheringController] Local SDP is valid");
|
|
14887
14979
|
this._iceCandidatesState.next({
|
|
14888
14980
|
state: "timeout",
|
|
14889
14981
|
validSDP
|
|
14890
14982
|
});
|
|
14891
14983
|
this.stopGathering();
|
|
14892
|
-
} else logger$
|
|
14984
|
+
} else logger$20.debug("### ICE gathering timeout\n", this.peerConnection.localDescription?.sdp);
|
|
14893
14985
|
}
|
|
14894
14986
|
handleICECandidateTimeout() {
|
|
14895
14987
|
if (this.iceCandidateTimer) this.removeTimer("iceCandidateTimer");
|
|
14896
|
-
logger$
|
|
14988
|
+
logger$20.warn("[ICEGatheringController] ICE candidate timeout");
|
|
14897
14989
|
const validSDP = this.hasValidLocalDescriptionSDP;
|
|
14898
14990
|
if (!validSDP && !this.relayOnly) this.restartICEGatheringWithRelayOnly();
|
|
14899
14991
|
else {
|
|
14900
|
-
logger$
|
|
14992
|
+
logger$20.debug("[ICEGatheringController] Using current SDP due to ICE candidate timeout");
|
|
14901
14993
|
this._iceCandidatesState.next({
|
|
14902
14994
|
state: "timeout",
|
|
14903
14995
|
validSDP
|
|
@@ -14906,22 +14998,22 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14906
14998
|
}
|
|
14907
14999
|
}
|
|
14908
15000
|
restartICEGatheringWithRelayOnly() {
|
|
14909
|
-
logger$
|
|
15001
|
+
logger$20.debug("[ICEGatheringController] Restarting ICE gathering with relay-only candidates");
|
|
14910
15002
|
this.relayOnly = true;
|
|
14911
15003
|
this.peerConnection.setConfiguration({
|
|
14912
15004
|
...this.peerConnection.getConfiguration(),
|
|
14913
15005
|
iceTransportPolicy: "relay"
|
|
14914
15006
|
});
|
|
14915
|
-
|
|
15007
|
+
this.peerConnection.restartIce();
|
|
14916
15008
|
}
|
|
14917
|
-
removeTimer(timer$
|
|
14918
|
-
if (this[timer$
|
|
14919
|
-
clearTimeout(this[timer$
|
|
14920
|
-
this[timer$
|
|
15009
|
+
removeTimer(timer$4) {
|
|
15010
|
+
if (this[timer$4]) {
|
|
15011
|
+
clearTimeout(this[timer$4]);
|
|
15012
|
+
this[timer$4] = void 0;
|
|
14921
15013
|
}
|
|
14922
15014
|
}
|
|
14923
15015
|
clearAllTimers() {
|
|
14924
|
-
logger$
|
|
15016
|
+
logger$20.debug("[ICEGatheringController] Clearing all timers");
|
|
14925
15017
|
this.removeTimer("iceGatheringTimer");
|
|
14926
15018
|
this.removeTimer("iceCandidateTimer");
|
|
14927
15019
|
}
|
|
@@ -14930,17 +15022,181 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
14930
15022
|
this.peerConnection.removeEventListener("icecandidate", this.onicecandidateHandler);
|
|
14931
15023
|
}
|
|
14932
15024
|
destroy() {
|
|
14933
|
-
logger$
|
|
15025
|
+
logger$20.debug("[ICEGatheringController] Destroying ICEGatheringController");
|
|
14934
15026
|
this.clearAllTimers();
|
|
14935
15027
|
this.removeEventListeners();
|
|
14936
15028
|
super.destroy();
|
|
14937
15029
|
}
|
|
14938
15030
|
};
|
|
14939
15031
|
|
|
15032
|
+
//#endregion
|
|
15033
|
+
//#region src/controllers/LocalAudioPipeline.ts
|
|
15034
|
+
var import_cjs$18 = require_cjs();
|
|
15035
|
+
const logger$19 = getLogger();
|
|
15036
|
+
/**
|
|
15037
|
+
* Web Audio pipeline for the local microphone stream.
|
|
15038
|
+
*
|
|
15039
|
+
* Wraps the raw mic `MediaStreamTrack` in a graph of:
|
|
15040
|
+
*
|
|
15041
|
+
* ```
|
|
15042
|
+
* MediaStreamAudioSourceNode → GainNode → AnalyserNode → MediaStreamAudioDestinationNode
|
|
15043
|
+
* ```
|
|
15044
|
+
*
|
|
15045
|
+
* The {@link outputTrack} from the destination node is what callers should
|
|
15046
|
+
* attach to the `RTCRtpSender` in place of the raw mic track. The same
|
|
15047
|
+
* destination track is reused across input changes (device switch, mute /
|
|
15048
|
+
* unmute track replacement) so the sender reference stays stable — only the
|
|
15049
|
+
* source end of the graph is rebuilt.
|
|
15050
|
+
*
|
|
15051
|
+
* The pipeline owns a single {@link AudioContext}. Callers must invoke
|
|
15052
|
+
* {@link destroy} to release it when the call ends.
|
|
15053
|
+
*/
|
|
15054
|
+
var LocalAudioPipeline = class extends Destroyable {
|
|
15055
|
+
constructor(options = {}) {
|
|
15056
|
+
super();
|
|
15057
|
+
this._inputSource = null;
|
|
15058
|
+
this._inputStream = null;
|
|
15059
|
+
this._lastSpokeAt = 0;
|
|
15060
|
+
this._gain$ = this.createBehaviorSubject(1);
|
|
15061
|
+
this._pttMultiplier = 1;
|
|
15062
|
+
this._audioContext = (options.audioContextFactory ?? (() => new AudioContext()))();
|
|
15063
|
+
this._gainNode = this._audioContext.createGain();
|
|
15064
|
+
this._analyser = this._audioContext.createAnalyser();
|
|
15065
|
+
this._analyser.fftSize = 2048;
|
|
15066
|
+
this._analyser.smoothingTimeConstant = .3;
|
|
15067
|
+
this._analyserBuffer = new Uint8Array(new ArrayBuffer(this._analyser.fftSize));
|
|
15068
|
+
this._destination = this._audioContext.createMediaStreamDestination();
|
|
15069
|
+
this._gainNode.connect(this._analyser);
|
|
15070
|
+
this._analyser.connect(this._destination);
|
|
15071
|
+
this._speakingThreshold = options.speakingThreshold ?? VAD_THRESHOLD;
|
|
15072
|
+
this._speakingHoldMs = options.speakingHoldMs ?? VAD_HOLD_MS;
|
|
15073
|
+
this._pollIntervalMs = options.pollIntervalMs ?? AUDIO_LEVEL_POLL_INTERVAL_MS;
|
|
15074
|
+
const initial = options.initialGain ?? 1;
|
|
15075
|
+
this._gain$.next(initial);
|
|
15076
|
+
this.applyEffectiveGain();
|
|
15077
|
+
}
|
|
15078
|
+
/** Observable of the current gain value (0..2). */
|
|
15079
|
+
get gain$() {
|
|
15080
|
+
return this._gain$.asObservable();
|
|
15081
|
+
}
|
|
15082
|
+
/** Current gain value (0..2). */
|
|
15083
|
+
get gain() {
|
|
15084
|
+
return this._gain$.value;
|
|
15085
|
+
}
|
|
15086
|
+
/**
|
|
15087
|
+
* Processed output track to attach to the RTCRtpSender. Stable reference
|
|
15088
|
+
* across input changes, so `sender.replaceTrack(pipeline.outputTrack)` only
|
|
15089
|
+
* needs to be called once.
|
|
15090
|
+
*/
|
|
15091
|
+
get outputTrack() {
|
|
15092
|
+
const [track] = this._destination.stream.getAudioTracks();
|
|
15093
|
+
return track;
|
|
15094
|
+
}
|
|
15095
|
+
/**
|
|
15096
|
+
* Root-mean-square audio level of the input signal, 0..1. Emits on a fixed
|
|
15097
|
+
* interval (~30fps by default).
|
|
15098
|
+
*/
|
|
15099
|
+
get level$() {
|
|
15100
|
+
return this.deferEmission((0, import_cjs$18.interval)(this._pollIntervalMs, import_cjs$18.animationFrameScheduler).pipe((0, import_cjs$18.map)(() => this.computeLevel())));
|
|
15101
|
+
}
|
|
15102
|
+
/**
|
|
15103
|
+
* Boolean VAD derived from {@link level$}. True while level ≥ threshold or
|
|
15104
|
+
* during the hold window after the last frame that crossed the threshold.
|
|
15105
|
+
*/
|
|
15106
|
+
get speaking$() {
|
|
15107
|
+
return this.deferEmission(this.level$.pipe((0, import_cjs$18.map)((level) => this.evaluateSpeaking(level)), (0, import_cjs$18.distinctUntilChanged)()));
|
|
15108
|
+
}
|
|
15109
|
+
/**
|
|
15110
|
+
* Set gain multiplier applied to the input signal. 0 = silence,
|
|
15111
|
+
* 1 = unity, 2 = 2x. Values are clamped to [0, 2]. The effective gain on
|
|
15112
|
+
* the graph also respects the current PTT state.
|
|
15113
|
+
*/
|
|
15114
|
+
setGain(value) {
|
|
15115
|
+
const clamped = Math.max(0, Math.min(2, value));
|
|
15116
|
+
this._gain$.next(clamped);
|
|
15117
|
+
this.applyEffectiveGain();
|
|
15118
|
+
}
|
|
15119
|
+
/**
|
|
15120
|
+
* Silence the graph when `active = false`, otherwise restore the configured
|
|
15121
|
+
* gain. Use this from a PTT handler: released → `false`, held → `true`.
|
|
15122
|
+
* Orthogonal to {@link setGain} — once PTT returns to active, the last
|
|
15123
|
+
* configured gain reappears.
|
|
15124
|
+
*/
|
|
15125
|
+
setPTTActive(active) {
|
|
15126
|
+
this._pttMultiplier = active ? 1 : 0;
|
|
15127
|
+
this.applyEffectiveGain();
|
|
15128
|
+
}
|
|
15129
|
+
applyEffectiveGain() {
|
|
15130
|
+
this._gainNode.gain.value = this._gain$.value * this._pttMultiplier;
|
|
15131
|
+
}
|
|
15132
|
+
/**
|
|
15133
|
+
* Wire a new raw mic track as the pipeline's input. Replaces any previous
|
|
15134
|
+
* input source and reconnects the graph so {@link outputTrack} continues
|
|
15135
|
+
* to emit the processed audio. Pass `null` to disconnect the input (the
|
|
15136
|
+
* output track stays alive but emits silence).
|
|
15137
|
+
*
|
|
15138
|
+
* Also resumes the underlying AudioContext on attach — Chrome creates it
|
|
15139
|
+
* in a suspended state and the graph won't process (the destination
|
|
15140
|
+
* track emits silence) until resume() succeeds.
|
|
15141
|
+
*/
|
|
15142
|
+
setInputTrack(track) {
|
|
15143
|
+
if (this._inputSource) {
|
|
15144
|
+
try {
|
|
15145
|
+
this._inputSource.disconnect();
|
|
15146
|
+
} catch (error) {
|
|
15147
|
+
logger$19.debug("[LocalAudioPipeline] input disconnect warning:", error);
|
|
15148
|
+
}
|
|
15149
|
+
this._inputSource = null;
|
|
15150
|
+
}
|
|
15151
|
+
if (this._inputStream) this._inputStream = null;
|
|
15152
|
+
if (!track) return;
|
|
15153
|
+
this._inputStream = new MediaStream([track]);
|
|
15154
|
+
this._inputSource = this._audioContext.createMediaStreamSource(this._inputStream);
|
|
15155
|
+
this._inputSource.connect(this._gainNode);
|
|
15156
|
+
if (this._audioContext.state === "suspended") this._audioContext.resume().catch((error) => {
|
|
15157
|
+
logger$19.warn("[LocalAudioPipeline] AudioContext resume failed:", error);
|
|
15158
|
+
});
|
|
15159
|
+
}
|
|
15160
|
+
destroy() {
|
|
15161
|
+
if (this._inputSource) {
|
|
15162
|
+
try {
|
|
15163
|
+
this._inputSource.disconnect();
|
|
15164
|
+
} catch {}
|
|
15165
|
+
this._inputSource = null;
|
|
15166
|
+
}
|
|
15167
|
+
try {
|
|
15168
|
+
this._gainNode.disconnect();
|
|
15169
|
+
this._analyser.disconnect();
|
|
15170
|
+
} catch {}
|
|
15171
|
+
this._audioContext.close().catch((error) => {
|
|
15172
|
+
logger$19.debug("[LocalAudioPipeline] audio context close warning:", error);
|
|
15173
|
+
});
|
|
15174
|
+
super.destroy();
|
|
15175
|
+
}
|
|
15176
|
+
computeLevel() {
|
|
15177
|
+
if (!this._inputSource) return 0;
|
|
15178
|
+
this._analyser.getByteTimeDomainData(this._analyserBuffer);
|
|
15179
|
+
let sum = 0;
|
|
15180
|
+
for (const sample$1 of this._analyserBuffer) {
|
|
15181
|
+
const normalized = (sample$1 - 128) / 128;
|
|
15182
|
+
sum += normalized * normalized;
|
|
15183
|
+
}
|
|
15184
|
+
return Math.sqrt(sum / this._analyserBuffer.length);
|
|
15185
|
+
}
|
|
15186
|
+
evaluateSpeaking(level) {
|
|
15187
|
+
const now = Date.now();
|
|
15188
|
+
if (level >= this._speakingThreshold) {
|
|
15189
|
+
this._lastSpokeAt = now;
|
|
15190
|
+
return true;
|
|
15191
|
+
}
|
|
15192
|
+
return now - this._lastSpokeAt < this._speakingHoldMs;
|
|
15193
|
+
}
|
|
15194
|
+
};
|
|
15195
|
+
|
|
14940
15196
|
//#endregion
|
|
14941
15197
|
//#region src/controllers/LocalStreamController.ts
|
|
14942
|
-
var import_cjs$
|
|
14943
|
-
const logger$
|
|
15198
|
+
var import_cjs$17 = require_cjs();
|
|
15199
|
+
const logger$18 = getLogger();
|
|
14944
15200
|
var LocalStreamController = class extends Destroyable {
|
|
14945
15201
|
constructor(options) {
|
|
14946
15202
|
super();
|
|
@@ -14954,16 +15210,16 @@ var LocalStreamController = class extends Destroyable {
|
|
|
14954
15210
|
this._mediaTrackEnded$ = this.createSubject();
|
|
14955
15211
|
}
|
|
14956
15212
|
get localStream$() {
|
|
14957
|
-
return this._localStream$.asObservable().pipe((0, import_cjs$
|
|
15213
|
+
return this._localStream$.asObservable().pipe((0, import_cjs$17.takeUntil)(this.destroyed$));
|
|
14958
15214
|
}
|
|
14959
15215
|
get localAudioTracks$() {
|
|
14960
|
-
return this._localAudioTracks$.asObservable().pipe((0, import_cjs$
|
|
15216
|
+
return this._localAudioTracks$.asObservable().pipe((0, import_cjs$17.takeUntil)(this.destroyed$));
|
|
14961
15217
|
}
|
|
14962
15218
|
get localVideoTracks$() {
|
|
14963
|
-
return this._localVideoTracks$.asObservable().pipe((0, import_cjs$
|
|
15219
|
+
return this._localVideoTracks$.asObservable().pipe((0, import_cjs$17.takeUntil)(this.destroyed$));
|
|
14964
15220
|
}
|
|
14965
15221
|
get mediaTrackEnded$() {
|
|
14966
|
-
return this._mediaTrackEnded$.asObservable().pipe((0, import_cjs$
|
|
15222
|
+
return this._mediaTrackEnded$.asObservable().pipe((0, import_cjs$17.takeUntil)(this.destroyed$));
|
|
14967
15223
|
}
|
|
14968
15224
|
get localStream() {
|
|
14969
15225
|
return this._localStream$.value;
|
|
@@ -14978,26 +15234,26 @@ var LocalStreamController = class extends Destroyable {
|
|
|
14978
15234
|
* Build the local media stream based on the provided options.
|
|
14979
15235
|
*/
|
|
14980
15236
|
async buildLocalStream() {
|
|
14981
|
-
logger$
|
|
15237
|
+
logger$18.debug("[LocalStreamController] Building local media stream.");
|
|
14982
15238
|
let stream;
|
|
14983
15239
|
if (this.options.inputAudioStream ?? this.options.inputVideoStream) {
|
|
14984
15240
|
const tracks = [...this.options.inputAudioStream?.getTracks() ?? [], ...this.options.inputVideoStream?.getTracks() ?? []];
|
|
14985
15241
|
stream = new MediaStream(tracks);
|
|
14986
15242
|
} else if (this.options.propose === "screenshare") {
|
|
14987
|
-
logger$
|
|
15243
|
+
logger$18.debug("[LocalStreamController] Requesting display media for screen sharing with audio:", Boolean(this.options.inputAudioDeviceConstraints));
|
|
14988
15244
|
stream = await this.options.getDisplayMedia({
|
|
14989
15245
|
video: true,
|
|
14990
15246
|
audio: Boolean(this.options.inputAudioDeviceConstraints)
|
|
14991
15247
|
});
|
|
14992
|
-
logger$
|
|
15248
|
+
logger$18.debug("[LocalStreamController] Screen share media obtained:", stream);
|
|
14993
15249
|
} else {
|
|
14994
15250
|
const constraints = {
|
|
14995
15251
|
audio: this.options.inputAudioDeviceConstraints,
|
|
14996
15252
|
video: this.options.inputVideoDeviceConstraints
|
|
14997
15253
|
};
|
|
14998
|
-
logger$
|
|
15254
|
+
logger$18.debug("[LocalStreamController] Requesting user media with constraints:", constraints);
|
|
14999
15255
|
stream = await this.options.getUserMedia(constraints);
|
|
15000
|
-
logger$
|
|
15256
|
+
logger$18.debug("[LocalStreamController] User media obtained:", stream);
|
|
15001
15257
|
}
|
|
15002
15258
|
this._localStream$.next(stream);
|
|
15003
15259
|
return stream;
|
|
@@ -15014,7 +15270,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15014
15270
|
this._localStream$.next(localStream);
|
|
15015
15271
|
if (track.kind === "video") this._localVideoTracks$.next(localStream.getVideoTracks());
|
|
15016
15272
|
else this._localAudioTracks$.next(localStream.getAudioTracks());
|
|
15017
|
-
logger$
|
|
15273
|
+
logger$18.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);
|
|
15018
15274
|
return localStream;
|
|
15019
15275
|
}
|
|
15020
15276
|
/**
|
|
@@ -15026,7 +15282,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15026
15282
|
const stream = this._localStream$.value;
|
|
15027
15283
|
const track = stream?.getTracks().find((t) => t.id === trackId);
|
|
15028
15284
|
if (!track) {
|
|
15029
|
-
logger$
|
|
15285
|
+
logger$18.debug(`[LocalStreamController] track not found: ${trackId}`);
|
|
15030
15286
|
return;
|
|
15031
15287
|
}
|
|
15032
15288
|
track.removeEventListener("ended", this.mediaTrackEndedHandler);
|
|
@@ -15035,7 +15291,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15035
15291
|
this._localStream$.next(stream);
|
|
15036
15292
|
if (track.kind === "video") this._localVideoTracks$.next(stream?.getVideoTracks() ?? []);
|
|
15037
15293
|
else this._localAudioTracks$.next(stream?.getAudioTracks() ?? []);
|
|
15038
|
-
logger$
|
|
15294
|
+
logger$18.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);
|
|
15039
15295
|
return track;
|
|
15040
15296
|
}
|
|
15041
15297
|
/**
|
|
@@ -15070,7 +15326,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15070
15326
|
*/
|
|
15071
15327
|
stopAllTracks() {
|
|
15072
15328
|
this._localStream$.value?.getTracks().forEach((track) => {
|
|
15073
|
-
logger$
|
|
15329
|
+
logger$18.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);
|
|
15074
15330
|
track.removeEventListener("ended", this.mediaTrackEndedHandler);
|
|
15075
15331
|
track.stop();
|
|
15076
15332
|
});
|
|
@@ -15086,7 +15342,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
15086
15342
|
|
|
15087
15343
|
//#endregion
|
|
15088
15344
|
//#region src/controllers/TransceiverController.ts
|
|
15089
|
-
const logger$
|
|
15345
|
+
const logger$17 = getLogger();
|
|
15090
15346
|
const getDirection = (send, recv) => {
|
|
15091
15347
|
if (send && recv) return "sendrecv";
|
|
15092
15348
|
else if (send && !recv) return "sendonly";
|
|
@@ -15188,7 +15444,7 @@ var TransceiverController = class extends Destroyable {
|
|
|
15188
15444
|
sendEncodings: isAudio ? void 0 : this.sendEncodings,
|
|
15189
15445
|
streams: direction === "recvonly" ? void 0 : [localStream]
|
|
15190
15446
|
};
|
|
15191
|
-
logger$
|
|
15447
|
+
logger$17.debug(`[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`, {
|
|
15192
15448
|
transceiver,
|
|
15193
15449
|
transceiverParams
|
|
15194
15450
|
});
|
|
@@ -15196,11 +15452,11 @@ var TransceiverController = class extends Destroyable {
|
|
|
15196
15452
|
await transceiver.sender.replaceTrack(track);
|
|
15197
15453
|
transceiver.direction = transceiverParams.direction;
|
|
15198
15454
|
if (transceiverParams.streams?.some((stream) => Boolean(stream))) {
|
|
15199
|
-
logger$
|
|
15455
|
+
logger$17.debug(`[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`, transceiverParams.streams);
|
|
15200
15456
|
transceiver.sender.setStreams(...transceiverParams.streams);
|
|
15201
15457
|
}
|
|
15202
15458
|
} else {
|
|
15203
|
-
logger$
|
|
15459
|
+
logger$17.debug(`[TransceiverController] Adding new transceiver for local ${track.kind} track:`, track.id);
|
|
15204
15460
|
this.peerConnection.addTransceiver(track, transceiverParams);
|
|
15205
15461
|
}
|
|
15206
15462
|
}
|
|
@@ -15214,13 +15470,13 @@ var TransceiverController = class extends Destroyable {
|
|
|
15214
15470
|
if (options.updateTransceiverDirection) transceiver.direction = "inactive";
|
|
15215
15471
|
}
|
|
15216
15472
|
} catch (error) {
|
|
15217
|
-
logger$
|
|
15473
|
+
logger$17.error("[TransceiverController] stopTrackSender error", kind, error);
|
|
15218
15474
|
this.options.onError?.(new MediaTrackError("stopTrackSender", kind, error));
|
|
15219
15475
|
}
|
|
15220
15476
|
}
|
|
15221
15477
|
async restoreTrackSender(kind) {
|
|
15222
15478
|
try {
|
|
15223
|
-
logger$
|
|
15479
|
+
logger$17.debug("[TransceiverController] restoreTrackSender called", kind);
|
|
15224
15480
|
const constraints = {};
|
|
15225
15481
|
const transceivers = this.transceiverByKind(kind);
|
|
15226
15482
|
for (const transceiver of transceivers) {
|
|
@@ -15230,23 +15486,23 @@ var TransceiverController = class extends Destroyable {
|
|
|
15230
15486
|
if (trackKind === "audio" || trackKind === "video") constraints[trackKind] = this.getConstraintsFor(trackKind);
|
|
15231
15487
|
}
|
|
15232
15488
|
}
|
|
15233
|
-
logger$
|
|
15489
|
+
logger$17.debug("[TransceiverController] restoreTrackSender constraints:", constraints);
|
|
15234
15490
|
if (Object.keys(constraints).length === 0) {
|
|
15235
|
-
logger$
|
|
15491
|
+
logger$17.warn("[TransceiverController] restoreTrackSender: no tracks need restoration", kind);
|
|
15236
15492
|
return;
|
|
15237
15493
|
}
|
|
15238
15494
|
const newTracks = (await this.options.getUserMedia(constraints)).getTracks();
|
|
15239
|
-
logger$
|
|
15495
|
+
logger$17.debug("[TransceiverController] restoreTrackSender new tracks:", newTracks);
|
|
15240
15496
|
for (const newTrack of newTracks) {
|
|
15241
15497
|
this.options.localStreamController.addTrack(newTrack);
|
|
15242
15498
|
const trackKind = newTrack.kind;
|
|
15243
15499
|
const transceiverOfKind = this.transceiverByKind(trackKind)[0];
|
|
15244
15500
|
transceiverOfKind.direction = trackKind === "audio" ? this.audioDirection : this.videoDirection;
|
|
15245
|
-
logger$
|
|
15501
|
+
logger$17.debug("[TransceiverController] restoreTrackSender setting direction for", trackKind, transceiverOfKind.direction);
|
|
15246
15502
|
await transceiverOfKind.sender.replaceTrack(newTrack);
|
|
15247
15503
|
}
|
|
15248
15504
|
} catch (error) {
|
|
15249
|
-
logger$
|
|
15505
|
+
logger$17.error("[TransceiverController] restoreTrackSender error", kind, error);
|
|
15250
15506
|
this.options.onError?.(new MediaTrackError("restoreTrackSender", kind, error));
|
|
15251
15507
|
}
|
|
15252
15508
|
}
|
|
@@ -15287,14 +15543,14 @@ var TransceiverController = class extends Destroyable {
|
|
|
15287
15543
|
};
|
|
15288
15544
|
try {
|
|
15289
15545
|
await track.applyConstraints(constraintsToApply);
|
|
15290
|
-
logger$
|
|
15291
|
-
logger$
|
|
15546
|
+
logger$17.debug(`[TransceiverController] Updated ${kind} sender constraints:`, constraintsToApply);
|
|
15547
|
+
logger$17.debug(`[TransceiverController] Updated ${kind} sender constraints:`, track.getConstraints());
|
|
15292
15548
|
} catch (error) {
|
|
15293
|
-
logger$
|
|
15549
|
+
logger$17.warn(`[TransceiverController] applyConstraints failed for ${kind} track ${track.id}, attempting track replacement fallback:`, error);
|
|
15294
15550
|
try {
|
|
15295
15551
|
await this.replaceTrackFallback(sender, track, kind, constraintsToApply);
|
|
15296
15552
|
} catch (fallbackError) {
|
|
15297
|
-
logger$
|
|
15553
|
+
logger$17.warn(`[TransceiverController] Track replacement fallback also failed for ${kind} track:`, fallbackError);
|
|
15298
15554
|
this.options.onError?.(new MediaTrackError("updateSendersConstraints", kind, fallbackError));
|
|
15299
15555
|
}
|
|
15300
15556
|
}
|
|
@@ -15322,7 +15578,7 @@ var TransceiverController = class extends Destroyable {
|
|
|
15322
15578
|
if (!newTrack) throw new MediaTrackError("replaceTrackFallback", kind, /* @__PURE__ */ new Error("getUserMedia returned no track of the requested kind"));
|
|
15323
15579
|
await sender.replaceTrack(newTrack);
|
|
15324
15580
|
this.options.localStreamController.addTrack(newTrack);
|
|
15325
|
-
logger$
|
|
15581
|
+
logger$17.debug(`[TransceiverController] Track replacement fallback succeeded for ${kind}. New track: ${newTrack.id}`);
|
|
15326
15582
|
}
|
|
15327
15583
|
getMediaDirections() {
|
|
15328
15584
|
if (this.peerConnection.connectionState === "connected") return this.peerConnection.getTransceivers().reduce((acc, transceiver) => {
|
|
@@ -15352,60 +15608,60 @@ var TransceiverController = class extends Destroyable {
|
|
|
15352
15608
|
|
|
15353
15609
|
//#endregion
|
|
15354
15610
|
//#region src/controllers/RTCPeerConnectionController.ts
|
|
15355
|
-
var import_cjs$
|
|
15356
|
-
const logger$
|
|
15611
|
+
var import_cjs$16 = require_cjs();
|
|
15612
|
+
const logger$16 = getLogger();
|
|
15357
15613
|
var RTCPeerConnectionController = class extends Destroyable {
|
|
15358
15614
|
constructor(options = {}, remoteSessionDescription, deviceController) {
|
|
15359
15615
|
super();
|
|
15360
15616
|
this.options = options;
|
|
15361
15617
|
this.firstSDPExchangeCompleted = false;
|
|
15362
15618
|
this.negotiationNeeded$ = this.createSubject();
|
|
15363
|
-
this.localDescription$ = (0, import_cjs$
|
|
15619
|
+
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)(() => {
|
|
15364
15620
|
this.negotiationEnded();
|
|
15365
|
-
}), (0, import_cjs$
|
|
15621
|
+
}), (0, import_cjs$16.filter)(() => this.shouldEmitLocalDescription), (0, import_cjs$16.map)(() => this.peerConnection?.localDescription), filterNull(), (0, import_cjs$16.tap)((desc) => {
|
|
15366
15622
|
if (desc.type === "answer") this._type = "offer";
|
|
15367
|
-
}))), (0, import_cjs$
|
|
15623
|
+
}))), (0, import_cjs$16.shareReplay)(1), (0, import_cjs$16.takeUntil)(this.destroyed$));
|
|
15368
15624
|
this.connectionTimeout = 3e3;
|
|
15369
15625
|
this.oniceconnectionstatechangeHandler = () => {
|
|
15370
15626
|
if (this.peerConnection) {
|
|
15371
15627
|
const { iceConnectionState } = this.peerConnection;
|
|
15372
|
-
logger$
|
|
15628
|
+
logger$16.debug(`[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`);
|
|
15373
15629
|
this._iceConnectionState$.next(this.peerConnection.iceConnectionState);
|
|
15374
15630
|
}
|
|
15375
15631
|
};
|
|
15376
15632
|
this.onconnectionstatechangeHandler = () => {
|
|
15377
15633
|
if (this.peerConnection) {
|
|
15378
15634
|
const { connectionState } = this.peerConnection;
|
|
15379
|
-
logger$
|
|
15635
|
+
logger$16.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);
|
|
15380
15636
|
if (connectionState === "connected") this.removeConnectionTimer();
|
|
15381
15637
|
this._connectionState$.next(this.peerConnection.connectionState);
|
|
15382
15638
|
}
|
|
15383
15639
|
};
|
|
15384
15640
|
this.onsignalingstatechangeHandler = () => {
|
|
15385
|
-
logger$
|
|
15641
|
+
logger$16.debug(`[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`);
|
|
15386
15642
|
};
|
|
15387
15643
|
this.onicegatheringstatechangeHandler = () => {
|
|
15388
15644
|
if (this.peerConnection) this._iceGatheringState$.next(this.peerConnection.iceGatheringState);
|
|
15389
15645
|
};
|
|
15390
15646
|
this.onnegotiationneededHandler = (event) => {
|
|
15391
|
-
logger$
|
|
15647
|
+
logger$16.debug("[RTCPeerConnectionController] Negotiation needed event received.", event);
|
|
15392
15648
|
this.negotiationNeeded$.next();
|
|
15393
15649
|
};
|
|
15394
15650
|
this.updateSelectedInputDevice = async (kind, deviceInfo) => {
|
|
15395
15651
|
try {
|
|
15396
15652
|
const { localStream } = this;
|
|
15397
15653
|
if (!localStream) {
|
|
15398
|
-
logger$
|
|
15654
|
+
logger$16.warn("[RTCPeerConnectionController] No local stream available to update input device.");
|
|
15399
15655
|
return;
|
|
15400
15656
|
}
|
|
15401
|
-
logger$
|
|
15657
|
+
logger$16.debug(`[RTCPeerConnectionController] Updating selected ${kind} input device:`, localStream.getTracks());
|
|
15402
15658
|
const track = localStream.getTracks().find((track$1) => track$1.kind === kind);
|
|
15403
15659
|
if (track) {
|
|
15404
15660
|
this.transceiverController?.stopTrackSender(kind);
|
|
15405
|
-
this.
|
|
15406
|
-
logger$
|
|
15661
|
+
this.localStreamController.removeTrack(track.id);
|
|
15662
|
+
logger$16.debug(`[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`, localStream.getTracks());
|
|
15407
15663
|
if (!deviceInfo) {
|
|
15408
|
-
logger$
|
|
15664
|
+
logger$16.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
|
|
15409
15665
|
return;
|
|
15410
15666
|
}
|
|
15411
15667
|
const streamTrack = (await this.getUserMedia({ [kind]: {
|
|
@@ -15413,15 +15669,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15413
15669
|
...this.deviceController.deviceInfoToConstraints(deviceInfo)
|
|
15414
15670
|
} })).getTracks().find((t) => t.kind === kind);
|
|
15415
15671
|
if (streamTrack) {
|
|
15416
|
-
logger$
|
|
15417
|
-
this.
|
|
15672
|
+
logger$16.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);
|
|
15673
|
+
this.localStreamController.addTrack(streamTrack);
|
|
15418
15674
|
await this.transceiverController?.replaceSenderTrack(kind, streamTrack);
|
|
15419
|
-
logger$
|
|
15675
|
+
logger$16.debug(`[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`, this.localStream?.getTracks());
|
|
15420
15676
|
}
|
|
15421
15677
|
}
|
|
15422
|
-
logger$
|
|
15678
|
+
logger$16.debug(`[RTCPeerConnectionController] ${kind} input device selected:`, deviceInfo?.label);
|
|
15423
15679
|
} catch (error) {
|
|
15424
|
-
logger$
|
|
15680
|
+
logger$16.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);
|
|
15425
15681
|
this._errors$.next(toError(error));
|
|
15426
15682
|
throw error;
|
|
15427
15683
|
}
|
|
@@ -15438,6 +15694,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15438
15694
|
this._remoteDescription$ = this.createReplaySubject(1);
|
|
15439
15695
|
this._remoteStream$ = this.createBehaviorSubject(null);
|
|
15440
15696
|
this._remoteOfferMediaDirections = null;
|
|
15697
|
+
this._localAudioPipeline = null;
|
|
15441
15698
|
this.deviceController = deviceController ?? {};
|
|
15442
15699
|
this.id = options.callId ?? v4_default();
|
|
15443
15700
|
this._type = remoteSessionDescription ? "answer" : "offer";
|
|
@@ -15507,43 +15764,43 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15507
15764
|
};
|
|
15508
15765
|
}
|
|
15509
15766
|
get iceGatheringState$() {
|
|
15510
|
-
return this.cachedObservable("iceGatheringState$", () => this._iceGatheringState$.asObservable().pipe((0, import_cjs$
|
|
15767
|
+
return this.cachedObservable("iceGatheringState$", () => this._iceGatheringState$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15511
15768
|
}
|
|
15512
15769
|
get mediaTrackEnded$() {
|
|
15513
|
-
return this.cachedObservable("mediaTrackEnded$", () => this.localStreamController.mediaTrackEnded$.pipe((0, import_cjs$
|
|
15770
|
+
return this.cachedObservable("mediaTrackEnded$", () => this.localStreamController.mediaTrackEnded$.pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15514
15771
|
}
|
|
15515
15772
|
get errors$() {
|
|
15516
|
-
return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$
|
|
15773
|
+
return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15517
15774
|
}
|
|
15518
15775
|
get iceCandidates$() {
|
|
15519
|
-
return this.cachedObservable("iceCandidates$", () => this._iceCandidates$.asObservable().pipe((0, import_cjs$
|
|
15776
|
+
return this.cachedObservable("iceCandidates$", () => this._iceCandidates$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15520
15777
|
}
|
|
15521
15778
|
get initialized$() {
|
|
15522
|
-
return this.cachedObservable("initialized$", () => this._initialized$.asObservable().pipe((0, import_cjs$
|
|
15779
|
+
return this.cachedObservable("initialized$", () => this._initialized$.asObservable().pipe((0, import_cjs$16.filter)((initialized) => initialized), (0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15523
15780
|
}
|
|
15524
15781
|
get remoteDescription$() {
|
|
15525
|
-
return this.cachedObservable("remoteDescription$", () => this._remoteDescription$.asObservable().pipe((0, import_cjs$
|
|
15782
|
+
return this.cachedObservable("remoteDescription$", () => this._remoteDescription$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15526
15783
|
}
|
|
15527
15784
|
get localStream$() {
|
|
15528
|
-
return this.cachedObservable("localStream$", () => this.localStreamController.localStream$.pipe((0, import_cjs$
|
|
15785
|
+
return this.cachedObservable("localStream$", () => this.localStreamController.localStream$.pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15529
15786
|
}
|
|
15530
15787
|
get remoteStream$() {
|
|
15531
|
-
return this.cachedObservable("remoteStream$", () => this._remoteStream$.asObservable().pipe((0, import_cjs$
|
|
15788
|
+
return this.cachedObservable("remoteStream$", () => this._remoteStream$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15532
15789
|
}
|
|
15533
15790
|
get localAudioTracks$() {
|
|
15534
|
-
return this.cachedObservable("localAudioTracks$", () => this.localStreamController.localAudioTracks$.pipe((0, import_cjs$
|
|
15791
|
+
return this.cachedObservable("localAudioTracks$", () => this.localStreamController.localAudioTracks$.pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15535
15792
|
}
|
|
15536
15793
|
get localVideoTracks$() {
|
|
15537
|
-
return this.cachedObservable("localVideoTracks$", () => this.localStreamController.localVideoTracks$.pipe((0, import_cjs$
|
|
15794
|
+
return this.cachedObservable("localVideoTracks$", () => this.localStreamController.localVideoTracks$.pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15538
15795
|
}
|
|
15539
15796
|
get iceConnectionState$() {
|
|
15540
|
-
return this.cachedObservable("iceConnectionState$", () => this._iceConnectionState$.asObservable().pipe((0, import_cjs$
|
|
15797
|
+
return this.cachedObservable("iceConnectionState$", () => this._iceConnectionState$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15541
15798
|
}
|
|
15542
15799
|
get connectionState$() {
|
|
15543
|
-
return this.cachedObservable("connectionState$", () => this._connectionState$.asObservable().pipe((0, import_cjs$
|
|
15800
|
+
return this.cachedObservable("connectionState$", () => this._connectionState$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15544
15801
|
}
|
|
15545
15802
|
get signalingState$() {
|
|
15546
|
-
return this.cachedObservable("signalingState$", () => this._signalingState$.asObservable().pipe((0, import_cjs$
|
|
15803
|
+
return this.cachedObservable("signalingState$", () => this._signalingState$.asObservable().pipe((0, import_cjs$16.takeUntil)(this.destroyed$)));
|
|
15547
15804
|
}
|
|
15548
15805
|
get type() {
|
|
15549
15806
|
return this._type;
|
|
@@ -15656,17 +15913,17 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15656
15913
|
async doInit() {
|
|
15657
15914
|
try {
|
|
15658
15915
|
this.setupPeerConnection();
|
|
15659
|
-
this.subscribeTo(this.negotiationNeeded$.pipe((0, import_cjs$
|
|
15916
|
+
this.subscribeTo(this.negotiationNeeded$.pipe((0, import_cjs$16.auditTime)(0), (0, import_cjs$16.exhaustMap)(async () => this.startNegotiation())), {
|
|
15660
15917
|
next: () => {
|
|
15661
|
-
logger$
|
|
15918
|
+
logger$16.debug("[RTCPeerConnectionController] Start Negotiation completed successfully");
|
|
15662
15919
|
},
|
|
15663
15920
|
error: (error) => {
|
|
15664
|
-
logger$
|
|
15921
|
+
logger$16.error("[RTCPeerConnectionController] Start Negotiation error:", error);
|
|
15665
15922
|
this._errors$.next(toError(error));
|
|
15666
15923
|
}
|
|
15667
15924
|
});
|
|
15668
|
-
this.subscribeTo((0, import_cjs$
|
|
15669
|
-
logger$
|
|
15925
|
+
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]) => {
|
|
15926
|
+
logger$16.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {
|
|
15670
15927
|
kind,
|
|
15671
15928
|
deviceInfo
|
|
15672
15929
|
});
|
|
@@ -15683,7 +15940,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15683
15940
|
this._initialized$.next(true);
|
|
15684
15941
|
}
|
|
15685
15942
|
} catch (error) {
|
|
15686
|
-
logger$
|
|
15943
|
+
logger$16.error("[RTCPeerConnectionController] Initialization error:", error);
|
|
15687
15944
|
this._errors$.next(toError(error));
|
|
15688
15945
|
this.destroy();
|
|
15689
15946
|
}
|
|
@@ -15715,22 +15972,22 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15715
15972
|
}
|
|
15716
15973
|
async startNegotiation() {
|
|
15717
15974
|
if (this.isNegotiating) {
|
|
15718
|
-
logger$
|
|
15975
|
+
logger$16.debug("[RTCPeerConnectionController] Negotiation already in progress, skipping.");
|
|
15719
15976
|
return;
|
|
15720
15977
|
}
|
|
15721
15978
|
this.setupEventListeners();
|
|
15722
15979
|
if (this.type === "answer") {
|
|
15723
|
-
logger$
|
|
15980
|
+
logger$16.debug("[RTCPeerConnectionController] This is an answer type still, skipping offer creation.");
|
|
15724
15981
|
return;
|
|
15725
15982
|
}
|
|
15726
15983
|
this._isNegotiating$.next(true);
|
|
15727
|
-
logger$
|
|
15984
|
+
logger$16.debug("[RTCPeerConnectionController] Starting negotiation.");
|
|
15728
15985
|
try {
|
|
15729
15986
|
const { offerOptions } = this;
|
|
15730
|
-
logger$
|
|
15987
|
+
logger$16.debug("[RTCPeerConnectionController] Creating offer with options:", offerOptions);
|
|
15731
15988
|
await this.createOffer(offerOptions);
|
|
15732
15989
|
} catch (error) {
|
|
15733
|
-
logger$
|
|
15990
|
+
logger$16.error("[RTCPeerConnectionController] Error during negotiation:", error);
|
|
15734
15991
|
this._errors$.next(toError(error));
|
|
15735
15992
|
}
|
|
15736
15993
|
}
|
|
@@ -15746,14 +16003,14 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15746
16003
|
let readyToConnect = status !== "failed";
|
|
15747
16004
|
try {
|
|
15748
16005
|
if (status === "received" && sdp) {
|
|
15749
|
-
logger$
|
|
16006
|
+
logger$16.debug("[RTCPeerConnectionController] Received answer SDP:", sdp);
|
|
15750
16007
|
await this._setRemoteDescription({
|
|
15751
16008
|
type: "answer",
|
|
15752
16009
|
sdp
|
|
15753
16010
|
});
|
|
15754
16011
|
}
|
|
15755
16012
|
} catch (error) {
|
|
15756
|
-
logger$
|
|
16013
|
+
logger$16.error("[RTCPeerConnectionController] Error updating answer status:", error);
|
|
15757
16014
|
this._errors$.next(toError(error));
|
|
15758
16015
|
readyToConnect = false;
|
|
15759
16016
|
} finally {
|
|
@@ -15772,7 +16029,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15772
16029
|
await this.handleOfferReceived();
|
|
15773
16030
|
break;
|
|
15774
16031
|
case "failed":
|
|
15775
|
-
logger$
|
|
16032
|
+
logger$16.error("[RTCPeerConnectionController] Offer failed to be processed by remote.");
|
|
15776
16033
|
break;
|
|
15777
16034
|
case "sent":
|
|
15778
16035
|
default:
|
|
@@ -15804,7 +16061,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15804
16061
|
}
|
|
15805
16062
|
await this.setupLocalTracks();
|
|
15806
16063
|
const { answerOptions } = this;
|
|
15807
|
-
logger$
|
|
16064
|
+
logger$16.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
|
|
15808
16065
|
await this.createAnswer(answerOptions);
|
|
15809
16066
|
}
|
|
15810
16067
|
async handleOfferReceived() {
|
|
@@ -15812,7 +16069,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15812
16069
|
this._isNegotiating$.next(true);
|
|
15813
16070
|
await this._setRemoteDescription(this.sdpInit);
|
|
15814
16071
|
const { answerOptions } = this;
|
|
15815
|
-
logger$
|
|
16072
|
+
logger$16.debug("[RTCPeerConnectionController] Creating answer with options:", answerOptions);
|
|
15816
16073
|
await this.createAnswer(answerOptions);
|
|
15817
16074
|
}
|
|
15818
16075
|
readyToConnect() {
|
|
@@ -15820,7 +16077,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15820
16077
|
this.connectionTimer = setTimeout(() => {
|
|
15821
16078
|
this.removeConnectionTimer();
|
|
15822
16079
|
if (this.peerConnection?.connectionState !== "connected") {
|
|
15823
|
-
logger$
|
|
16080
|
+
logger$16.debug("[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.");
|
|
15824
16081
|
this.iceGatheringController.restartICEGatheringWithRelayOnly();
|
|
15825
16082
|
}
|
|
15826
16083
|
}, this.connectionTimeout);
|
|
@@ -15842,14 +16099,14 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15842
16099
|
const stereo = this.options.stereo ?? PreferencesContainer.instance.stereoAudio;
|
|
15843
16100
|
if (preferredAudioCodecs.length > 0 || preferredVideoCodecs.length > 0) {
|
|
15844
16101
|
result = setCodecPreferences(result, preferredAudioCodecs, preferredVideoCodecs);
|
|
15845
|
-
logger$
|
|
16102
|
+
logger$16.debug("[RTCPeerConnectionController] Applied codec preferences to SDP", {
|
|
15846
16103
|
preferredAudioCodecs,
|
|
15847
16104
|
preferredVideoCodecs
|
|
15848
16105
|
});
|
|
15849
16106
|
}
|
|
15850
16107
|
if (stereo) {
|
|
15851
16108
|
result = enableStereoOpus(result);
|
|
15852
|
-
logger$
|
|
16109
|
+
logger$16.debug("[RTCPeerConnectionController] Applied stereo Opus to SDP");
|
|
15853
16110
|
}
|
|
15854
16111
|
return Promise.resolve(result);
|
|
15855
16112
|
}
|
|
@@ -15883,9 +16140,6 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15883
16140
|
negotiationEnded() {
|
|
15884
16141
|
this._isNegotiating$.next(false);
|
|
15885
16142
|
}
|
|
15886
|
-
restarIce() {
|
|
15887
|
-
this.peerConnection?.restartIce();
|
|
15888
|
-
}
|
|
15889
16143
|
/**
|
|
15890
16144
|
* Trigger an ICE restart through the existing negotiation pipeline.
|
|
15891
16145
|
*
|
|
@@ -15908,24 +16162,27 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15908
16162
|
...this.peerConnection.getConfiguration(),
|
|
15909
16163
|
iceTransportPolicy: "relay"
|
|
15910
16164
|
});
|
|
15911
|
-
logger$
|
|
16165
|
+
logger$16.debug("[RTCPeerConnectionController] ICE transport policy set to relay-only");
|
|
15912
16166
|
} catch (error) {
|
|
15913
|
-
logger$
|
|
16167
|
+
logger$16.warn("[RTCPeerConnectionController] Failed to set relay-only policy:", error);
|
|
15914
16168
|
}
|
|
15915
16169
|
this.setupEventListeners();
|
|
15916
16170
|
this._isNegotiating$.next(true);
|
|
15917
|
-
logger$
|
|
16171
|
+
logger$16.debug(`[RTCPeerConnectionController] Triggering ICE restart${relayOnly ? " (relay-only)" : ""}.`);
|
|
15918
16172
|
try {
|
|
15919
16173
|
const offer = await this.peerConnection.createOffer({ iceRestart: true });
|
|
15920
16174
|
await this.setLocalDescription(offer);
|
|
15921
16175
|
} catch (error) {
|
|
15922
|
-
logger$
|
|
16176
|
+
logger$16.error("[RTCPeerConnectionController] ICE restart offer failed:", error);
|
|
15923
16177
|
this._errors$.next(toError(error));
|
|
15924
16178
|
this.negotiationEnded();
|
|
15925
16179
|
if (policyChanged) this.restoreIceTransportPolicy();
|
|
15926
16180
|
throw error;
|
|
15927
16181
|
}
|
|
15928
|
-
if (policyChanged) this.restoreIceTransportPolicy()
|
|
16182
|
+
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) => {
|
|
16183
|
+
logger$16.warn("[RTCPeerConnectionController] Error waiting for ICE gathering to complete:", error);
|
|
16184
|
+
this.restoreIceTransportPolicy();
|
|
16185
|
+
});
|
|
15929
16186
|
}
|
|
15930
16187
|
restoreIceTransportPolicy() {
|
|
15931
16188
|
try {
|
|
@@ -15933,9 +16190,9 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15933
16190
|
...this.peerConnection.getConfiguration(),
|
|
15934
16191
|
iceTransportPolicy: this.options.relayOnly ? "relay" : "all"
|
|
15935
16192
|
});
|
|
15936
|
-
logger$
|
|
16193
|
+
logger$16.debug("[RTCPeerConnectionController] ICE transport policy restored");
|
|
15937
16194
|
} catch (error) {
|
|
15938
|
-
logger$
|
|
16195
|
+
logger$16.warn("[RTCPeerConnectionController] Failed to restore ICE transport policy:", error);
|
|
15939
16196
|
}
|
|
15940
16197
|
}
|
|
15941
16198
|
/**
|
|
@@ -15947,13 +16204,13 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15947
16204
|
await this.setupRemoteTracks();
|
|
15948
16205
|
}
|
|
15949
16206
|
async setupLocalTracks() {
|
|
15950
|
-
logger$
|
|
16207
|
+
logger$16.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
|
|
15951
16208
|
const localStream = this.localStream ?? await this.localStreamController.buildLocalStream();
|
|
15952
16209
|
if (this.transceiverController?.useAddStream ?? false) {
|
|
15953
|
-
logger$
|
|
16210
|
+
logger$16.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
|
|
15954
16211
|
this.peerConnection?.addStream(localStream);
|
|
15955
16212
|
if (!this.isNegotiating) {
|
|
15956
|
-
logger$
|
|
16213
|
+
logger$16.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
|
|
15957
16214
|
this.negotiationNeeded$.next();
|
|
15958
16215
|
}
|
|
15959
16216
|
return;
|
|
@@ -15969,7 +16226,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15969
16226
|
const transceivers = (kind === "audio" ? this.transceiverController?.audioTransceivers : this.transceiverController?.videoTransceivers) ?? [];
|
|
15970
16227
|
await this.transceiverController?.setupTransceiverSender(track, localStream, transceivers[index]);
|
|
15971
16228
|
} else {
|
|
15972
|
-
logger$
|
|
16229
|
+
logger$16.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
|
|
15973
16230
|
this.peerConnection?.addTrack(track, localStream);
|
|
15974
16231
|
}
|
|
15975
16232
|
}
|
|
@@ -15986,7 +16243,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15986
16243
|
async setupRemoteTracks() {
|
|
15987
16244
|
if (!this.peerConnection) throw new DependencyError("RTCPeerConnection is not initialized");
|
|
15988
16245
|
this.peerConnection.ontrack = (event) => {
|
|
15989
|
-
logger$
|
|
16246
|
+
logger$16.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
|
|
15990
16247
|
if (event.streams[0]) this._remoteStream$.next(event.streams[0]);
|
|
15991
16248
|
else {
|
|
15992
16249
|
const existingTracks = this._remoteStream$.value?.getTracks() ?? [];
|
|
@@ -15998,6 +16255,45 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
15998
16255
|
}
|
|
15999
16256
|
async restoreTrackSender(kind) {
|
|
16000
16257
|
await this.transceiverController?.restoreTrackSender(kind);
|
|
16258
|
+
if (kind !== "video" && this._localAudioPipeline) await this.applyLocalAudioPipelineToSender();
|
|
16259
|
+
}
|
|
16260
|
+
/**
|
|
16261
|
+
* Return the lazily-created {@link LocalAudioPipeline}, constructing it on
|
|
16262
|
+
* first access. On creation the current audio sender's track is routed
|
|
16263
|
+
* through the pipeline (input → gain → analyser → destination) and the
|
|
16264
|
+
* sender is switched to emit the processed track. Returns `null` when no
|
|
16265
|
+
* audio sender exists yet (pre-negotiation).
|
|
16266
|
+
*/
|
|
16267
|
+
ensureLocalAudioPipeline() {
|
|
16268
|
+
if (this._localAudioPipeline) return this._localAudioPipeline;
|
|
16269
|
+
if (!this.peerConnection) return null;
|
|
16270
|
+
try {
|
|
16271
|
+
this._localAudioPipeline = new LocalAudioPipeline();
|
|
16272
|
+
} catch (error) {
|
|
16273
|
+
logger$16.warn("[RTCPeerConnectionController] Failed to create LocalAudioPipeline:", error);
|
|
16274
|
+
return null;
|
|
16275
|
+
}
|
|
16276
|
+
this.subscribeTo(this.localStreamController.localAudioTracks$, () => {
|
|
16277
|
+
this.applyLocalAudioPipelineToSender();
|
|
16278
|
+
});
|
|
16279
|
+
this.applyLocalAudioPipelineToSender();
|
|
16280
|
+
return this._localAudioPipeline;
|
|
16281
|
+
}
|
|
16282
|
+
/** The active LocalAudioPipeline, or null if it hasn't been created yet. */
|
|
16283
|
+
get localAudioPipeline() {
|
|
16284
|
+
return this._localAudioPipeline;
|
|
16285
|
+
}
|
|
16286
|
+
async applyLocalAudioPipelineToSender() {
|
|
16287
|
+
if (!this._localAudioPipeline || !this.peerConnection) return;
|
|
16288
|
+
const raw = this.localStreamController.localAudioTracks.at(0);
|
|
16289
|
+
this._localAudioPipeline.setInputTrack(raw ?? null);
|
|
16290
|
+
const sender = (this.transceiverController?.audioTransceivers.at(0))?.sender ?? this.peerConnection.getSenders().find((s) => s.track?.kind === "audio");
|
|
16291
|
+
if (!sender || !raw) return;
|
|
16292
|
+
try {
|
|
16293
|
+
await sender.replaceTrack(this._localAudioPipeline.outputTrack);
|
|
16294
|
+
} catch (error) {
|
|
16295
|
+
logger$16.warn("[RTCPeerConnectionController] Failed to route audio sender through pipeline:", error);
|
|
16296
|
+
}
|
|
16001
16297
|
}
|
|
16002
16298
|
/**
|
|
16003
16299
|
* Add a local media track to the peer connection.
|
|
@@ -16012,9 +16308,9 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16012
16308
|
try {
|
|
16013
16309
|
const localStream = this.localStreamController.addTrack(track);
|
|
16014
16310
|
this.peerConnection.addTrack(track, localStream);
|
|
16015
|
-
logger$
|
|
16311
|
+
logger$16.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);
|
|
16016
16312
|
} catch (error) {
|
|
16017
|
-
logger$
|
|
16313
|
+
logger$16.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);
|
|
16018
16314
|
this._errors$.next(toError(error));
|
|
16019
16315
|
throw error;
|
|
16020
16316
|
}
|
|
@@ -16031,15 +16327,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16031
16327
|
}
|
|
16032
16328
|
const sender = this.peerConnection.getSenders().find((sender$1) => sender$1.track?.id === trackId);
|
|
16033
16329
|
if (!sender) {
|
|
16034
|
-
logger$
|
|
16330
|
+
logger$16.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);
|
|
16035
16331
|
return;
|
|
16036
16332
|
}
|
|
16037
16333
|
try {
|
|
16038
16334
|
this.peerConnection.removeTrack(sender);
|
|
16039
16335
|
this.localStreamController.removeTrack(trackId);
|
|
16040
|
-
logger$
|
|
16336
|
+
logger$16.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);
|
|
16041
16337
|
} catch (error) {
|
|
16042
|
-
logger$
|
|
16338
|
+
logger$16.error(`[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`, error);
|
|
16043
16339
|
this._errors$.next(toError(error));
|
|
16044
16340
|
throw error;
|
|
16045
16341
|
}
|
|
@@ -16066,7 +16362,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16066
16362
|
async replaceAudioTrackWithConstraints(constraints) {
|
|
16067
16363
|
const senders = this.peerConnection?.getSenders().filter((s) => s.track?.kind === "audio" && s.track.readyState === "live");
|
|
16068
16364
|
if (!senders || senders.length === 0) {
|
|
16069
|
-
logger$
|
|
16365
|
+
logger$16.warn("[RTCPeerConnectionController] No live audio sender to replace");
|
|
16070
16366
|
return;
|
|
16071
16367
|
}
|
|
16072
16368
|
for (const sender of senders) {
|
|
@@ -16084,7 +16380,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16084
16380
|
const newTrack = (await this.getUserMedia({ audio: mergedConstraints })).getAudioTracks()[0];
|
|
16085
16381
|
await sender.replaceTrack(newTrack);
|
|
16086
16382
|
this.localStreamController.addTrack(newTrack);
|
|
16087
|
-
logger$
|
|
16383
|
+
logger$16.debug(`[RTCPeerConnectionController] Audio track replaced for server-pushed params. New track: ${newTrack.id}`);
|
|
16088
16384
|
}
|
|
16089
16385
|
}
|
|
16090
16386
|
/**
|
|
@@ -16092,9 +16388,11 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16092
16388
|
* Completes all observables to prevent memory leaks.
|
|
16093
16389
|
*/
|
|
16094
16390
|
destroy() {
|
|
16095
|
-
logger$
|
|
16391
|
+
logger$16.debug(`[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`);
|
|
16096
16392
|
this.removeConnectionTimer();
|
|
16097
16393
|
this._iceGatheringController?.destroy();
|
|
16394
|
+
this._localAudioPipeline?.destroy();
|
|
16395
|
+
this._localAudioPipeline = null;
|
|
16098
16396
|
this.localStreamController.destroy();
|
|
16099
16397
|
this.transceiverController?.destroy();
|
|
16100
16398
|
if (this.peerConnection) {
|
|
@@ -16116,7 +16414,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16116
16414
|
}
|
|
16117
16415
|
stopRemoteTracks() {
|
|
16118
16416
|
this._remoteStream$.value?.getTracks().forEach((track) => {
|
|
16119
|
-
logger$
|
|
16417
|
+
logger$16.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);
|
|
16120
16418
|
track.stop();
|
|
16121
16419
|
});
|
|
16122
16420
|
}
|
|
@@ -16133,7 +16431,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
16133
16431
|
...params,
|
|
16134
16432
|
sdp: finalRemote
|
|
16135
16433
|
};
|
|
16136
|
-
logger$
|
|
16434
|
+
logger$16.debug("[RTCPeerConnectionController] Setting remote description:", answer);
|
|
16137
16435
|
return this.peerConnection.setRemoteDescription(answer);
|
|
16138
16436
|
}
|
|
16139
16437
|
};
|
|
@@ -16171,8 +16469,25 @@ function isVertoPingInnerParams(value) {
|
|
|
16171
16469
|
|
|
16172
16470
|
//#endregion
|
|
16173
16471
|
//#region src/managers/VertoManager.ts
|
|
16174
|
-
var import_cjs$
|
|
16175
|
-
const logger$
|
|
16472
|
+
var import_cjs$15 = require_cjs();
|
|
16473
|
+
const logger$15 = getLogger();
|
|
16474
|
+
/**
|
|
16475
|
+
* Decide what value goes on the `node_id` field of a `webrtc.verto` envelope.
|
|
16476
|
+
*
|
|
16477
|
+
* - **Reattach invite:** must carry the persisted nodeId so the server routes
|
|
16478
|
+
* the new connection to the FreeSWITCH instance that holds the existing call.
|
|
16479
|
+
* - **Fresh invite, caller-supplied `CallOptions.nodeId`:** carry the explicit
|
|
16480
|
+
* value as a steering hint (dev/staging traffic pinning). Server may honour
|
|
16481
|
+
* or ignore for placement reasons.
|
|
16482
|
+
* - **Fresh invite, no caller nodeId:** strip to `''` = "server picks".
|
|
16483
|
+
* - **Non-invite frames** (verto.modify, verto.bye, etc.): always carry the
|
|
16484
|
+
* current `_nodeId$.value` so the frame targets the node hosting the call.
|
|
16485
|
+
*
|
|
16486
|
+
* Pure function — exported for unit testing.
|
|
16487
|
+
*/
|
|
16488
|
+
function resolveInviteNodeId(args) {
|
|
16489
|
+
return args.isInvite && !args.reattach && !args.explicitNodeId ? "" : args.currentNodeId ?? "";
|
|
16490
|
+
}
|
|
16176
16491
|
var VertoManager = class extends Destroyable {
|
|
16177
16492
|
constructor(callSession) {
|
|
16178
16493
|
super();
|
|
@@ -16211,7 +16526,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16211
16526
|
try {
|
|
16212
16527
|
await this.executeVerto(vertoModifyMessage);
|
|
16213
16528
|
} catch (error) {
|
|
16214
|
-
logger$
|
|
16529
|
+
logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto hold:", error);
|
|
16215
16530
|
throw error;
|
|
16216
16531
|
}
|
|
16217
16532
|
}
|
|
@@ -16224,7 +16539,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16224
16539
|
try {
|
|
16225
16540
|
await this.executeVerto(vertoModifyMessage);
|
|
16226
16541
|
} catch (error) {
|
|
16227
|
-
logger$
|
|
16542
|
+
logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto unhold:", error);
|
|
16228
16543
|
throw error;
|
|
16229
16544
|
}
|
|
16230
16545
|
}
|
|
@@ -16264,7 +16579,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16264
16579
|
return rtcPeerConnection;
|
|
16265
16580
|
}
|
|
16266
16581
|
get signalingStatus$() {
|
|
16267
|
-
return this.cachedObservable("signalingStatus$", () => (0, import_cjs$
|
|
16582
|
+
return this.cachedObservable("signalingStatus$", () => (0, import_cjs$15.merge)(this._signalingStatus$.asObservable(), this.mainPeerConnection.connectionState$.pipe((0, import_cjs$15.filter)((connectionState) => [
|
|
16268
16583
|
"connected",
|
|
16269
16584
|
"disconnected",
|
|
16270
16585
|
"failed"
|
|
@@ -16277,7 +16592,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16277
16592
|
if (event.member_id) this.setSelfIdIfNull(event.member_id);
|
|
16278
16593
|
});
|
|
16279
16594
|
this.subscribeTo(this.vertoMedia$, (event) => {
|
|
16280
|
-
logger$
|
|
16595
|
+
logger$15.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
|
|
16281
16596
|
this._signalingStatus$.next("ringing");
|
|
16282
16597
|
const { sdp, callID } = event;
|
|
16283
16598
|
this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
|
|
@@ -16286,7 +16601,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16286
16601
|
});
|
|
16287
16602
|
});
|
|
16288
16603
|
this.subscribeTo(this.vertoAnswer$, (event) => {
|
|
16289
|
-
logger$
|
|
16604
|
+
logger$15.debug("[WebRTCManager] Received Verto answer event:", event);
|
|
16290
16605
|
this._signalingStatus$.next("connecting");
|
|
16291
16606
|
const { sdp, callID } = event;
|
|
16292
16607
|
this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
|
|
@@ -16295,7 +16610,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16295
16610
|
});
|
|
16296
16611
|
});
|
|
16297
16612
|
this.subscribeTo(this.vertoMediaParams$, (event) => {
|
|
16298
|
-
logger$
|
|
16613
|
+
logger$15.debug("[WebRTCManager] Received Verto mediaParams event:", event);
|
|
16299
16614
|
const { mediaParams, callID } = event;
|
|
16300
16615
|
const rtcPeerConnController = this._rtcPeerConnectionsMap.get(callID);
|
|
16301
16616
|
const { audio, video } = mediaParams;
|
|
@@ -16309,7 +16624,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16309
16624
|
timestamp: Date.now()
|
|
16310
16625
|
});
|
|
16311
16626
|
} catch (error) {
|
|
16312
|
-
logger$
|
|
16627
|
+
logger$15.warn("[WebRTCManager] Error applying server-pushed media params:", error);
|
|
16313
16628
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16314
16629
|
}
|
|
16315
16630
|
})();
|
|
@@ -16331,13 +16646,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16331
16646
|
*/
|
|
16332
16647
|
setNodeIdIfNull(nodeId) {
|
|
16333
16648
|
if (!this._nodeId$.value && nodeId) {
|
|
16334
|
-
logger$
|
|
16649
|
+
logger$15.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
|
|
16335
16650
|
this._nodeId$.next(nodeId);
|
|
16336
16651
|
}
|
|
16337
16652
|
}
|
|
16338
16653
|
setSelfIdIfNull(selfId) {
|
|
16339
16654
|
if (!this._selfId$.value && selfId) {
|
|
16340
|
-
logger$
|
|
16655
|
+
logger$15.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
|
|
16341
16656
|
this._selfId$.next(selfId);
|
|
16342
16657
|
}
|
|
16343
16658
|
}
|
|
@@ -16346,7 +16661,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16346
16661
|
const vertoPongMessage = VertoPong({ ...vertoPing });
|
|
16347
16662
|
await this.executeVerto(vertoPongMessage);
|
|
16348
16663
|
} catch (error) {
|
|
16349
|
-
logger$
|
|
16664
|
+
logger$15.warn("[WebRTCManager] Call might disconnect, error sending Verto pong:", error);
|
|
16350
16665
|
this.onError?.(new VertoPongError(error));
|
|
16351
16666
|
}
|
|
16352
16667
|
}
|
|
@@ -16356,7 +16671,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16356
16671
|
if (audio) await this.mainPeerConnection.updateSendersConstraints("audio", audio);
|
|
16357
16672
|
if (video) await this.mainPeerConnection.updateSendersConstraints("video", video);
|
|
16358
16673
|
} catch (error) {
|
|
16359
|
-
logger$
|
|
16674
|
+
logger$15.warn("[WebRTCManager] Error updating media constraints:", error);
|
|
16360
16675
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16361
16676
|
throw error;
|
|
16362
16677
|
}
|
|
@@ -16386,20 +16701,20 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16386
16701
|
try {
|
|
16387
16702
|
const pc = this.mainPeerConnection.peerConnection;
|
|
16388
16703
|
if (!pc) {
|
|
16389
|
-
logger$
|
|
16704
|
+
logger$15.warn("[WebRTCManager] No peer connection for keyframe request");
|
|
16390
16705
|
return;
|
|
16391
16706
|
}
|
|
16392
16707
|
const videoReceiver = pc.getReceivers().find((r) => r.track.kind === "video");
|
|
16393
16708
|
if (!videoReceiver) {
|
|
16394
|
-
logger$
|
|
16709
|
+
logger$15.warn("[WebRTCManager] No video receiver for keyframe request");
|
|
16395
16710
|
return;
|
|
16396
16711
|
}
|
|
16397
16712
|
if (typeof videoReceiver.requestKeyFrame === "function") {
|
|
16398
16713
|
videoReceiver.requestKeyFrame();
|
|
16399
|
-
logger$
|
|
16400
|
-
} else logger$
|
|
16714
|
+
logger$15.debug("[WebRTCManager] Keyframe requested via RTCRtpReceiver.requestKeyFrame()");
|
|
16715
|
+
} else logger$15.debug("[WebRTCManager] requestKeyFrame() not supported, skipping");
|
|
16401
16716
|
} catch (error) {
|
|
16402
|
-
logger$
|
|
16717
|
+
logger$15.warn("[WebRTCManager] Keyframe request failed (non-fatal):", error);
|
|
16403
16718
|
}
|
|
16404
16719
|
}
|
|
16405
16720
|
/**
|
|
@@ -16417,13 +16732,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16417
16732
|
try {
|
|
16418
16733
|
const controller = this.mainPeerConnection;
|
|
16419
16734
|
if (!controller.peerConnection) {
|
|
16420
|
-
logger$
|
|
16735
|
+
logger$15.warn("[WebRTCManager] No peer connection for ICE restart");
|
|
16421
16736
|
return;
|
|
16422
16737
|
}
|
|
16423
16738
|
await controller.triggerIceRestart(relayOnly);
|
|
16424
|
-
logger$
|
|
16739
|
+
logger$15.info(`[WebRTCManager] ICE restart initiated${relayOnly ? " (relay-only)" : ""}`);
|
|
16425
16740
|
} catch (error) {
|
|
16426
|
-
logger$
|
|
16741
|
+
logger$15.error("[WebRTCManager] ICE restart failed:", error);
|
|
16427
16742
|
throw error;
|
|
16428
16743
|
}
|
|
16429
16744
|
}
|
|
@@ -16441,13 +16756,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16441
16756
|
const entries = Array.from(this._rtcPeerConnectionsMap.entries());
|
|
16442
16757
|
for (const [id, controller] of entries) try {
|
|
16443
16758
|
if (!controller.peerConnection) {
|
|
16444
|
-
logger$
|
|
16759
|
+
logger$15.debug(`[WebRTCManager] No peer connection for leg ${id}, skipping ICE restart`);
|
|
16445
16760
|
continue;
|
|
16446
16761
|
}
|
|
16447
16762
|
await controller.triggerIceRestart(relayOnly);
|
|
16448
|
-
logger$
|
|
16763
|
+
logger$15.info(`[WebRTCManager] ICE restart initiated for leg ${id}${relayOnly ? " (relay-only)" : ""}`);
|
|
16449
16764
|
} catch (error) {
|
|
16450
|
-
logger$
|
|
16765
|
+
logger$15.warn(`[WebRTCManager] ICE restart failed for leg ${id}:`, error);
|
|
16451
16766
|
}
|
|
16452
16767
|
}
|
|
16453
16768
|
/**
|
|
@@ -16459,7 +16774,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16459
16774
|
requestKeyframeAll() {
|
|
16460
16775
|
for (const [id, controller] of this._rtcPeerConnectionsMap) {
|
|
16461
16776
|
if (controller.isScreenShare) {
|
|
16462
|
-
logger$
|
|
16777
|
+
logger$15.debug(`[WebRTCManager] Skipping keyframe for send-only screen share leg ${id}`);
|
|
16463
16778
|
continue;
|
|
16464
16779
|
}
|
|
16465
16780
|
try {
|
|
@@ -16469,33 +16784,33 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16469
16784
|
if (!videoReceiver) continue;
|
|
16470
16785
|
if (typeof videoReceiver.requestKeyFrame === "function") {
|
|
16471
16786
|
videoReceiver.requestKeyFrame();
|
|
16472
|
-
logger$
|
|
16787
|
+
logger$15.debug(`[WebRTCManager] Keyframe requested for leg ${id}`);
|
|
16473
16788
|
}
|
|
16474
16789
|
} catch (error) {
|
|
16475
|
-
logger$
|
|
16790
|
+
logger$15.warn(`[WebRTCManager] Keyframe request failed for leg ${id} (non-fatal):`, error);
|
|
16476
16791
|
}
|
|
16477
16792
|
}
|
|
16478
16793
|
}
|
|
16479
16794
|
get callJoinedEvent$() {
|
|
16480
|
-
return this.webRtcCallSession.callEvent$.pipe((0, import_cjs$
|
|
16795
|
+
return this.webRtcCallSession.callEvent$.pipe((0, import_cjs$15.filter)(isCallJoinedPayload), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16481
16796
|
}
|
|
16482
16797
|
get vertoMedia$() {
|
|
16483
|
-
return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$
|
|
16798
|
+
return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16484
16799
|
}
|
|
16485
16800
|
get vertoAnswer$() {
|
|
16486
|
-
return this.cachedObservable("vertoAnswer$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAnswerInnerParams, "params"), (0, import_cjs$
|
|
16801
|
+
return this.cachedObservable("vertoAnswer$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAnswerInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16487
16802
|
}
|
|
16488
16803
|
get vertoMediaParams$() {
|
|
16489
|
-
return this.cachedObservable("vertoMediaParams$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaParamsInnerParams, "params"), (0, import_cjs$
|
|
16804
|
+
return this.cachedObservable("vertoMediaParams$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaParamsInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16490
16805
|
}
|
|
16491
16806
|
get vertoBye$() {
|
|
16492
|
-
return this.cachedObservable("vertoBye$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoByeMessage, "params"), (0, import_cjs$
|
|
16807
|
+
return this.cachedObservable("vertoBye$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoByeMessage, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16493
16808
|
}
|
|
16494
16809
|
get vertoAttach$() {
|
|
16495
|
-
return this.cachedObservable("vertoAttach$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAttachMessage, "params"), (0, import_cjs$
|
|
16810
|
+
return this.cachedObservable("vertoAttach$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAttachMessage, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16496
16811
|
}
|
|
16497
16812
|
get vertoPing$() {
|
|
16498
|
-
return this.cachedObservable("vertoPing$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoPingInnerParams, "params"), (0, import_cjs$
|
|
16813
|
+
return this.cachedObservable("vertoPing$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoPingInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16499
16814
|
}
|
|
16500
16815
|
async executeVerto(message, optionals = {}) {
|
|
16501
16816
|
const webrtcVertoMessage = WebrtcVerto({
|
|
@@ -16533,7 +16848,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16533
16848
|
default:
|
|
16534
16849
|
}
|
|
16535
16850
|
} catch (error) {
|
|
16536
|
-
logger$
|
|
16851
|
+
logger$15.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
|
|
16537
16852
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16538
16853
|
if (vertoMethod === "verto.modify") this.onModifyFailed?.();
|
|
16539
16854
|
}
|
|
@@ -16548,7 +16863,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16548
16863
|
sdp
|
|
16549
16864
|
});
|
|
16550
16865
|
} catch (error) {
|
|
16551
|
-
logger$
|
|
16866
|
+
logger$15.warn("[WebRTCManager] Error processing modify response:", error);
|
|
16552
16867
|
const modifyError = error instanceof Error ? error : new Error(String(error), { cause: error });
|
|
16553
16868
|
this.onError?.(modifyError);
|
|
16554
16869
|
}
|
|
@@ -16560,7 +16875,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16560
16875
|
this._nodeId$.next(getValueFrom(response, "result.node_id") ?? null);
|
|
16561
16876
|
const memberId = getValueFrom(response, "result.result.result.memberID") ?? null;
|
|
16562
16877
|
const callId = getValueFrom(response, "result.result.result.callID") ?? null;
|
|
16563
|
-
logger$
|
|
16878
|
+
logger$15.debug("[WebRTCManager] Verto invite response:", {
|
|
16564
16879
|
callId,
|
|
16565
16880
|
memberId,
|
|
16566
16881
|
response
|
|
@@ -16570,14 +16885,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16570
16885
|
if (callId) {
|
|
16571
16886
|
this.webRtcCallSession.addCallId(callId);
|
|
16572
16887
|
this.attachManager.attach(this.buildAttachableCall(callId));
|
|
16573
|
-
} else logger$
|
|
16888
|
+
} else logger$15.warn("[WebRTCManager] Cannot attach call, missing callId:", {
|
|
16574
16889
|
nodeId: this.nodeId,
|
|
16575
16890
|
callId
|
|
16576
16891
|
});
|
|
16577
|
-
logger$
|
|
16578
|
-
logger$
|
|
16892
|
+
logger$15.info("[WebRTCManager] Verto invite successful");
|
|
16893
|
+
logger$15.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
|
|
16579
16894
|
} else {
|
|
16580
|
-
logger$
|
|
16895
|
+
logger$15.error("[WebRTCManager] Verto invite failed:", response);
|
|
16581
16896
|
const inviteError = response.error ? new JSONRPCError(response.error.code, response.error.message, response.error.data) : /* @__PURE__ */ new Error("Verto invite failed: unexpected response");
|
|
16582
16897
|
this.onError?.(inviteError);
|
|
16583
16898
|
}
|
|
@@ -16622,17 +16937,17 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16622
16937
|
if (options.initOffer) this.handleInboundAnswer(rtcPeerConnController);
|
|
16623
16938
|
}
|
|
16624
16939
|
async handleInboundAnswer(rtcPeerConnController) {
|
|
16625
|
-
logger$
|
|
16626
|
-
const vertoByeOrAccepted = await (0, import_cjs$
|
|
16940
|
+
logger$15.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
|
|
16941
|
+
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);
|
|
16627
16942
|
if (vertoByeOrAccepted === null) {
|
|
16628
|
-
logger$
|
|
16943
|
+
logger$15.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
|
|
16629
16944
|
return;
|
|
16630
16945
|
}
|
|
16631
16946
|
if (isVertoByeMessage(vertoByeOrAccepted)) {
|
|
16632
|
-
logger$
|
|
16947
|
+
logger$15.info("[WebRTCManager] Inbound call ended by remote before answer.");
|
|
16633
16948
|
this.callSession?.destroy();
|
|
16634
16949
|
} else if (!vertoByeOrAccepted) {
|
|
16635
|
-
logger$
|
|
16950
|
+
logger$15.info("[WebRTCManager] Inbound call rejected by user.");
|
|
16636
16951
|
try {
|
|
16637
16952
|
await this.bye("USER_BUSY");
|
|
16638
16953
|
} finally {
|
|
@@ -16640,19 +16955,19 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16640
16955
|
this.callSession?.destroy();
|
|
16641
16956
|
}
|
|
16642
16957
|
} else {
|
|
16643
|
-
logger$
|
|
16958
|
+
logger$15.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
|
|
16644
16959
|
const answerOptions = this.webRtcCallSession.answerMediaOptions;
|
|
16645
16960
|
try {
|
|
16646
16961
|
await rtcPeerConnController.acceptInbound(answerOptions);
|
|
16647
16962
|
} catch (error) {
|
|
16648
|
-
logger$
|
|
16963
|
+
logger$15.error("[WebRTCManager] Error creating inbound answer:", error);
|
|
16649
16964
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16650
16965
|
}
|
|
16651
16966
|
}
|
|
16652
16967
|
}
|
|
16653
16968
|
setupVertoAttachHandler() {
|
|
16654
16969
|
this.subscribeTo(this.vertoAttach$, async (vertoAttach) => {
|
|
16655
|
-
logger$
|
|
16970
|
+
logger$15.debug("[WebRTCManager] Received Verto attach event for existing call:", vertoAttach);
|
|
16656
16971
|
const { callID } = vertoAttach;
|
|
16657
16972
|
await this.attachManager.attach({
|
|
16658
16973
|
nodeId: this.nodeId ?? void 0,
|
|
@@ -16666,12 +16981,12 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16666
16981
|
});
|
|
16667
16982
|
}
|
|
16668
16983
|
initObservables(rtcPeerConnController) {
|
|
16669
|
-
this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, import_cjs$
|
|
16670
|
-
this.localStream$ = rtcPeerConnController.localStream$.pipe(filterNull(), (0, import_cjs$
|
|
16671
|
-
this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(filterNull(), (0, import_cjs$
|
|
16984
|
+
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$));
|
|
16985
|
+
this.localStream$ = rtcPeerConnController.localStream$.pipe(filterNull(), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16986
|
+
this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(filterNull(), (0, import_cjs$15.takeUntil)(this.destroyed$));
|
|
16672
16987
|
}
|
|
16673
16988
|
setupLocalDescriptionHandler(rtcPeerConnController) {
|
|
16674
|
-
this.subscribeTo(rtcPeerConnController.localDescription$.pipe((0, import_cjs$
|
|
16989
|
+
this.subscribeTo(rtcPeerConnController.localDescription$.pipe((0, import_cjs$15.filter)((description) => description !== null), (0, import_cjs$15.takeUntil)(this.destroyed$)), (description) => {
|
|
16675
16990
|
const { type, sdp } = description;
|
|
16676
16991
|
const dialogParams = this.dialogParams(rtcPeerConnController);
|
|
16677
16992
|
const initial = !rtcPeerConnController.firstSDPExchangeCompleted;
|
|
@@ -16712,26 +17027,29 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16712
17027
|
else if (rtcPeerConnController.isAdditionalDevice) subscribe.push(...PreferencesContainer.instance.inviteSubscribeAdditionalDevice);
|
|
16713
17028
|
else if (rtcPeerConnController.isScreenShare) subscribe.push(...PreferencesContainer.instance.inviteSubscribeScreenshare);
|
|
16714
17029
|
}
|
|
16715
|
-
const isInvite = isVertoInviteMessage(vertoMessage);
|
|
16716
|
-
const isReattach = isInvite && this.webRtcCallSession.options.reattach;
|
|
16717
17030
|
return {
|
|
16718
17031
|
callID: rtcPeerConnController.id,
|
|
16719
|
-
node_id:
|
|
17032
|
+
node_id: resolveInviteNodeId({
|
|
17033
|
+
isInvite: isVertoInviteMessage(vertoMessage),
|
|
17034
|
+
reattach: this.webRtcCallSession.options.reattach === true,
|
|
17035
|
+
explicitNodeId: this.webRtcCallSession.options.nodeId,
|
|
17036
|
+
currentNodeId: this._nodeId$.value
|
|
17037
|
+
}),
|
|
16720
17038
|
subscribe
|
|
16721
17039
|
};
|
|
16722
17040
|
}
|
|
16723
17041
|
async sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnectionController) {
|
|
16724
|
-
logger$
|
|
16725
|
-
const vertoByeOrAccepted = await (0, import_cjs$
|
|
17042
|
+
logger$15.debug("[WebRTCManager] Waiting for call to be accepted or ended before sending answer");
|
|
17043
|
+
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);
|
|
16726
17044
|
if (vertoByeOrAccepted === null) {
|
|
16727
|
-
logger$
|
|
17045
|
+
logger$15.debug("[WebRTCManager] Destroyed while waiting for call acceptance");
|
|
16728
17046
|
return;
|
|
16729
17047
|
}
|
|
16730
17048
|
if (isVertoByeMessage(vertoByeOrAccepted)) {
|
|
16731
|
-
logger$
|
|
17049
|
+
logger$15.info("[WebRTCManager] Call ended before answer was sent.");
|
|
16732
17050
|
this.callSession?.destroy();
|
|
16733
17051
|
} else if (!vertoByeOrAccepted) {
|
|
16734
|
-
logger$
|
|
17052
|
+
logger$15.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
|
|
16735
17053
|
try {
|
|
16736
17054
|
await this.bye("USER_BUSY");
|
|
16737
17055
|
} finally {
|
|
@@ -16739,14 +17057,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16739
17057
|
this.callSession?.destroy();
|
|
16740
17058
|
}
|
|
16741
17059
|
} else {
|
|
16742
|
-
logger$
|
|
17060
|
+
logger$15.debug("[WebRTCManager] Call accepted, sending answer");
|
|
16743
17061
|
try {
|
|
16744
17062
|
this._signalingStatus$.next("connecting");
|
|
16745
17063
|
await this.sendLocalDescription(vertoMessageRequest, rtcPeerConnectionController);
|
|
16746
17064
|
await rtcPeerConnectionController.updateAnswerStatus({ status: "sent" });
|
|
16747
17065
|
await this.attachManager.attach(this.buildAttachableCall());
|
|
16748
17066
|
} catch (error) {
|
|
16749
|
-
logger$
|
|
17067
|
+
logger$15.error("[WebRTCManager] Error sending Verto answer:", error);
|
|
16750
17068
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16751
17069
|
await rtcPeerConnectionController.updateAnswerStatus({ status: "failed" });
|
|
16752
17070
|
}
|
|
@@ -16787,6 +17105,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16787
17105
|
async unmuteMainVideoInputDevice() {
|
|
16788
17106
|
return this.mainPeerConnection.restoreTrackSender("video");
|
|
16789
17107
|
}
|
|
17108
|
+
/** Get or lazily create the local audio pipeline for the main peer connection. */
|
|
17109
|
+
ensureLocalAudioPipeline() {
|
|
17110
|
+
return this.mainPeerConnection.ensureLocalAudioPipeline();
|
|
17111
|
+
}
|
|
17112
|
+
/** The currently-active local audio pipeline, or null if it hasn't been created. */
|
|
17113
|
+
get localAudioPipeline() {
|
|
17114
|
+
return this.mainPeerConnection.localAudioPipeline;
|
|
17115
|
+
}
|
|
16790
17116
|
async addInputDevice(options = {
|
|
16791
17117
|
audio: false,
|
|
16792
17118
|
video: true
|
|
@@ -16835,12 +17161,12 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16835
17161
|
this.subscribeTo(rtcPeerConnController.errors$, (error) => {
|
|
16836
17162
|
this.onError?.(error);
|
|
16837
17163
|
});
|
|
16838
|
-
await (0, import_cjs$
|
|
17164
|
+
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$)));
|
|
16839
17165
|
this._screenShareStatus$.next("started");
|
|
16840
|
-
logger$
|
|
17166
|
+
logger$15.info("[WebRTCManager] Screen share started successfully.");
|
|
16841
17167
|
return rtcPeerConnController.id;
|
|
16842
17168
|
} catch (error) {
|
|
16843
|
-
logger$
|
|
17169
|
+
logger$15.warn("[WebRTCManager] Error initializing additional peer connection:", error);
|
|
16844
17170
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16845
17171
|
if (rtcPeerConnController) rtcPeerConnController.destroy();
|
|
16846
17172
|
this._screenShareStatus$.next("none");
|
|
@@ -16859,9 +17185,9 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16859
17185
|
if (removeTrack) return this.mainPeerConnection.stopTrackSender(removeTrack, { updateTransceiverDirection: true });
|
|
16860
17186
|
}
|
|
16861
17187
|
async removeScreenMedia() {
|
|
16862
|
-
if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$
|
|
17188
|
+
if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$15.warn("[WebRTCManager] No active screen share to stop.");
|
|
16863
17189
|
if (!this._screenShareId) {
|
|
16864
|
-
logger$
|
|
17190
|
+
logger$15.debug("[WebRTCManager] No screen share peer connection found.");
|
|
16865
17191
|
return;
|
|
16866
17192
|
}
|
|
16867
17193
|
this._screenShareStatus$.next("stopping");
|
|
@@ -16890,7 +17216,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16890
17216
|
dialogParams: this.dialogParams(rtcPeerConnController)
|
|
16891
17217
|
}));
|
|
16892
17218
|
} catch (error) {
|
|
16893
|
-
logger$
|
|
17219
|
+
logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto bye:", error);
|
|
16894
17220
|
throw error;
|
|
16895
17221
|
}
|
|
16896
17222
|
}
|
|
@@ -16908,7 +17234,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16908
17234
|
try {
|
|
16909
17235
|
await this.executeVerto(vertoInfoMessage);
|
|
16910
17236
|
} catch (error) {
|
|
16911
|
-
logger$
|
|
17237
|
+
logger$15.warn("[WebRTCManager] Error sending DTMF digits:", error);
|
|
16912
17238
|
throw error;
|
|
16913
17239
|
}
|
|
16914
17240
|
}
|
|
@@ -16919,10 +17245,10 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16919
17245
|
action: "transfer"
|
|
16920
17246
|
});
|
|
16921
17247
|
try {
|
|
16922
|
-
logger$
|
|
17248
|
+
logger$15.debug("[WebRTCManager] Transferring call with options:", options);
|
|
16923
17249
|
await this.executeVerto(message);
|
|
16924
17250
|
} catch (error) {
|
|
16925
|
-
logger$
|
|
17251
|
+
logger$15.error("[WebRTCManager] Error transferring call:", error);
|
|
16926
17252
|
throw error;
|
|
16927
17253
|
}
|
|
16928
17254
|
}
|
|
@@ -16936,6 +17262,77 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16936
17262
|
}
|
|
16937
17263
|
};
|
|
16938
17264
|
|
|
17265
|
+
//#endregion
|
|
17266
|
+
//#region src/controllers/RemoteAudioMeter.ts
|
|
17267
|
+
var import_cjs$14 = require_cjs();
|
|
17268
|
+
const logger$14 = getLogger();
|
|
17269
|
+
/**
|
|
17270
|
+
* Read-only audio level meter for a remote MediaStream. Attaches an
|
|
17271
|
+
* AnalyserNode to a MediaStreamAudioSourceNode so it observes the stream
|
|
17272
|
+
* without affecting the caller's playback path (no GainNode, no destination).
|
|
17273
|
+
*
|
|
17274
|
+
* The server delivers all remote audio as a single mixed stream — there is
|
|
17275
|
+
* no per-participant demux — so this meter reports the aggregate remote
|
|
17276
|
+
* level, not per-member.
|
|
17277
|
+
*/
|
|
17278
|
+
var RemoteAudioMeter = class extends Destroyable {
|
|
17279
|
+
constructor(options = {}) {
|
|
17280
|
+
super();
|
|
17281
|
+
this._source = null;
|
|
17282
|
+
this._stream = null;
|
|
17283
|
+
this._audioContext = (options.audioContextFactory ?? (() => new AudioContext()))();
|
|
17284
|
+
this._analyser = this._audioContext.createAnalyser();
|
|
17285
|
+
this._analyser.fftSize = 2048;
|
|
17286
|
+
this._analyser.smoothingTimeConstant = .3;
|
|
17287
|
+
this._analyserBuffer = new Uint8Array(new ArrayBuffer(this._analyser.fftSize));
|
|
17288
|
+
this._pollIntervalMs = options.pollIntervalMs ?? AUDIO_LEVEL_POLL_INTERVAL_MS;
|
|
17289
|
+
}
|
|
17290
|
+
/** RMS level of the remote audio, 0..1. 0 when no stream is attached. */
|
|
17291
|
+
get level$() {
|
|
17292
|
+
return this.deferEmission((0, import_cjs$14.interval)(this._pollIntervalMs, import_cjs$14.animationFrameScheduler).pipe((0, import_cjs$14.map)(() => this.computeLevel())));
|
|
17293
|
+
}
|
|
17294
|
+
/**
|
|
17295
|
+
* Attach (or replace) the MediaStream whose audio track is being metered.
|
|
17296
|
+
* Pass null to detach without destroying the meter.
|
|
17297
|
+
*/
|
|
17298
|
+
setStream(stream) {
|
|
17299
|
+
if (this._source) {
|
|
17300
|
+
try {
|
|
17301
|
+
this._source.disconnect();
|
|
17302
|
+
} catch (error) {
|
|
17303
|
+
logger$14.debug("[RemoteAudioMeter] source disconnect warning:", error);
|
|
17304
|
+
}
|
|
17305
|
+
this._source = null;
|
|
17306
|
+
this._stream = null;
|
|
17307
|
+
}
|
|
17308
|
+
if (!stream || stream.getAudioTracks().length === 0) return;
|
|
17309
|
+
this._stream = new MediaStream(stream.getAudioTracks());
|
|
17310
|
+
this._source = this._audioContext.createMediaStreamSource(this._stream);
|
|
17311
|
+
}
|
|
17312
|
+
destroy() {
|
|
17313
|
+
if (this._source) {
|
|
17314
|
+
try {
|
|
17315
|
+
this._source.disconnect();
|
|
17316
|
+
} catch {}
|
|
17317
|
+
this._source = null;
|
|
17318
|
+
}
|
|
17319
|
+
this._audioContext.close().catch((error) => {
|
|
17320
|
+
logger$14.debug("[RemoteAudioMeter] audio context close warning:", error);
|
|
17321
|
+
});
|
|
17322
|
+
super.destroy();
|
|
17323
|
+
}
|
|
17324
|
+
computeLevel() {
|
|
17325
|
+
if (!this._source) return 0;
|
|
17326
|
+
this._analyser.getByteTimeDomainData(this._analyserBuffer);
|
|
17327
|
+
let sum = 0;
|
|
17328
|
+
for (const sample$1 of this._analyserBuffer) {
|
|
17329
|
+
const normalized = (sample$1 - 128) / 128;
|
|
17330
|
+
sum += normalized * normalized;
|
|
17331
|
+
}
|
|
17332
|
+
return Math.sqrt(sum / this._analyserBuffer.length);
|
|
17333
|
+
}
|
|
17334
|
+
};
|
|
17335
|
+
|
|
16939
17336
|
//#endregion
|
|
16940
17337
|
//#region src/controllers/RTCStatsMonitor.ts
|
|
16941
17338
|
var import_cjs$13 = require_cjs();
|
|
@@ -17093,11 +17490,11 @@ var RTCStatsMonitor = class extends Destroyable {
|
|
|
17093
17490
|
let availableOutgoingBitrate;
|
|
17094
17491
|
report.forEach((stat) => {
|
|
17095
17492
|
if (isInboundRtpStat(stat)) if (stat.kind === "audio") {
|
|
17096
|
-
audioPacketsReceived += stat.packetsReceived ??
|
|
17493
|
+
audioPacketsReceived += stat.packetsReceived ?? 0;
|
|
17097
17494
|
audioPacketsLost += stat.packetsLost ?? 0;
|
|
17098
17495
|
audioJitter = Math.max(audioJitter, (stat.jitter ?? 0) * 1e3);
|
|
17099
17496
|
} else {
|
|
17100
|
-
videoPacketsReceived += stat.packetsReceived ??
|
|
17497
|
+
videoPacketsReceived += stat.packetsReceived ?? 0;
|
|
17101
17498
|
videoPacketsLost += stat.packetsLost ?? 0;
|
|
17102
17499
|
}
|
|
17103
17500
|
if (isCandidatePairStat(stat) && stat.state === "succeeded" && stat.nominated) {
|
|
@@ -17749,6 +18146,8 @@ var WebRTCCall = class extends Destroyable {
|
|
|
17749
18146
|
this._bandwidthConstrained$ = this.createBehaviorSubject(false);
|
|
17750
18147
|
this._mediaParamsUpdated$ = this.createSubject();
|
|
17751
18148
|
this._customSubscriptions = /* @__PURE__ */ new Map();
|
|
18149
|
+
this._pushToTalkEnabled = false;
|
|
18150
|
+
this._remoteAudioMeter = null;
|
|
17752
18151
|
this.id = options.callId ?? v4_default();
|
|
17753
18152
|
this.to = options.to;
|
|
17754
18153
|
this._userVariables$.next({
|
|
@@ -18147,10 +18546,10 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18147
18546
|
try {
|
|
18148
18547
|
if (this.vertoManager.requestIceRestartAll) await this.vertoManager.requestIceRestartAll(relayOnly);
|
|
18149
18548
|
else await this.vertoManager.requestIceRestart?.(relayOnly);
|
|
18150
|
-
return true;
|
|
18151
18549
|
} catch {
|
|
18152
18550
|
return false;
|
|
18153
18551
|
}
|
|
18552
|
+
return this.waitForPeerConnectionConnected();
|
|
18154
18553
|
},
|
|
18155
18554
|
disableVideo: () => {
|
|
18156
18555
|
try {
|
|
@@ -18242,6 +18641,27 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18242
18641
|
}
|
|
18243
18642
|
}
|
|
18244
18643
|
/**
|
|
18644
|
+
* Wait for the underlying RTCPeerConnection to reach 'connected' after
|
|
18645
|
+
* triggering an ICE restart. Resolves true on success, false on failure
|
|
18646
|
+
* or if the state doesn't transition within the configured timeout.
|
|
18647
|
+
*
|
|
18648
|
+
* Polls connectionState directly because the recovery manager already
|
|
18649
|
+
* wraps this call in its own withTimeout(); a separate listener-based
|
|
18650
|
+
* implementation would race the outer timeout in subtle ways.
|
|
18651
|
+
*/
|
|
18652
|
+
async waitForPeerConnectionConnected() {
|
|
18653
|
+
const pc = this.rtcPeerConnection;
|
|
18654
|
+
if (!pc) return false;
|
|
18655
|
+
const deadline = Date.now() + PEER_CONNECTION_RECOVERY_WAIT_MS;
|
|
18656
|
+
for (;;) {
|
|
18657
|
+
const state = pc.connectionState;
|
|
18658
|
+
if (state === "connected") return true;
|
|
18659
|
+
if (state === "failed" || state === "closed") return false;
|
|
18660
|
+
if (Date.now() >= deadline) return false;
|
|
18661
|
+
await new Promise((resolve) => setTimeout(resolve, PEER_CONNECTION_RECOVERY_POLL_MS));
|
|
18662
|
+
}
|
|
18663
|
+
}
|
|
18664
|
+
/**
|
|
18245
18665
|
* @internal Stop and destroy resilience subsystems (on disconnect/destroy).
|
|
18246
18666
|
* Clears references so they can be re-created on reconnect.
|
|
18247
18667
|
*/
|
|
@@ -18378,8 +18798,13 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18378
18798
|
const cached = this._customSubscriptions.get(eventType);
|
|
18379
18799
|
if (cached) return cached;
|
|
18380
18800
|
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$));
|
|
18801
|
+
this._sendVertoSubscribe(eventType).then(() => {
|
|
18802
|
+
this._customSubscriptions.set(eventType, filtered$);
|
|
18803
|
+
}, (error) => {
|
|
18804
|
+
this._customSubscriptions.delete(eventType);
|
|
18805
|
+
logger$11.warn(`[Call] verto.subscribe for '${eventType}' failed, not caching:`, error);
|
|
18806
|
+
});
|
|
18381
18807
|
this._customSubscriptions.set(eventType, filtered$);
|
|
18382
|
-
this._sendVertoSubscribe(eventType);
|
|
18383
18808
|
return filtered$;
|
|
18384
18809
|
}
|
|
18385
18810
|
get webrtcMessages$() {
|
|
@@ -18494,37 +18919,156 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18494
18919
|
async transfer(options) {
|
|
18495
18920
|
return this.vertoManager.transfer(options);
|
|
18496
18921
|
}
|
|
18922
|
+
/**
|
|
18923
|
+
* Set the local microphone gain as a percentage applied before transmission.
|
|
18924
|
+
*
|
|
18925
|
+
* - `0` = silent
|
|
18926
|
+
* - `100` = unity (no change, default)
|
|
18927
|
+
* - `200` = 2× digital boost (max; expect clipping / noise amplification)
|
|
18928
|
+
*
|
|
18929
|
+
* Values are clamped to [0, 200]. Engages the local audio pipeline on
|
|
18930
|
+
* first use (one-time cost).
|
|
18931
|
+
*
|
|
18932
|
+
* Note: this is a **digital** multiplier applied in a Web Audio GainNode
|
|
18933
|
+
* between your mic track and the RTCRtpSender — it does not change the
|
|
18934
|
+
* physical mic's hardware sensitivity. Browsers' autoGainControl can
|
|
18935
|
+
* fight the setting; call {@link setAutoGainControl}(false) for
|
|
18936
|
+
* predictable behaviour.
|
|
18937
|
+
*
|
|
18938
|
+
* @param value - Gain percentage (0..200; 100 = unity).
|
|
18939
|
+
*/
|
|
18940
|
+
setLocalMicrophoneGain(value) {
|
|
18941
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18942
|
+
if (!pipeline) {
|
|
18943
|
+
logger$11.warn("[Call] setLocalMicrophoneGain: audio pipeline unavailable");
|
|
18944
|
+
return;
|
|
18945
|
+
}
|
|
18946
|
+
const percent = Math.max(0, Math.min(200, value));
|
|
18947
|
+
pipeline.setGain(percent / 100);
|
|
18948
|
+
}
|
|
18949
|
+
/** Observable of the current local microphone gain (0..200, where 100 = unity). */
|
|
18950
|
+
get localMicrophoneGain$() {
|
|
18951
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18952
|
+
if (!pipeline) return (0, import_cjs$11.of)(100).pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
|
|
18953
|
+
return this.publicCachedObservable("localMicrophoneGain$", () => pipeline.gain$.pipe((0, import_cjs$11.map)((multiplier) => multiplier * 100), (0, import_cjs$11.takeUntil)(this._destroyed$)));
|
|
18954
|
+
}
|
|
18955
|
+
/**
|
|
18956
|
+
* Observable of the RMS audio level of the local microphone, 0..1.
|
|
18957
|
+
* Emits at ~30fps while a mic track is active. Engages the local audio
|
|
18958
|
+
* pipeline on first subscription.
|
|
18959
|
+
*/
|
|
18960
|
+
get localAudioLevel$() {
|
|
18961
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18962
|
+
if (!pipeline) return (0, import_cjs$11.of)(0).pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
|
|
18963
|
+
return this.publicCachedObservable("localAudioLevel$", () => pipeline.level$.pipe((0, import_cjs$11.takeUntil)(this._destroyed$), (0, import_cjs$11.share)()));
|
|
18964
|
+
}
|
|
18965
|
+
/**
|
|
18966
|
+
* Observable that is `true` while the local participant is speaking
|
|
18967
|
+
* (RMS level above the VAD threshold, with hold time to avoid flicker).
|
|
18968
|
+
*/
|
|
18969
|
+
get localSpeaking$() {
|
|
18970
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18971
|
+
if (!pipeline) return (0, import_cjs$11.of)(false).pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
|
|
18972
|
+
return this.publicCachedObservable("localSpeaking$", () => pipeline.speaking$.pipe((0, import_cjs$11.takeUntil)(this._destroyed$), (0, import_cjs$11.share)()));
|
|
18973
|
+
}
|
|
18974
|
+
/**
|
|
18975
|
+
* Enable push-to-talk: while {@link setPushToTalkActive} has been called
|
|
18976
|
+
* with `false`, the microphone gain is forced to 0; calling
|
|
18977
|
+
* {@link setPushToTalkActive} with `true` restores the configured gain.
|
|
18978
|
+
* Use this instead of mute/unmute for instant talk/silence transitions
|
|
18979
|
+
* because it doesn't rebuild the track.
|
|
18980
|
+
*
|
|
18981
|
+
* This method installs the pipeline but does not attach any keyboard
|
|
18982
|
+
* listener — consumers bind the key themselves and call
|
|
18983
|
+
* {@link setPushToTalkActive} on keydown/keyup.
|
|
18984
|
+
*/
|
|
18985
|
+
enablePushToTalk() {
|
|
18986
|
+
const pipeline = this.vertoManager.ensureLocalAudioPipeline();
|
|
18987
|
+
if (!pipeline) {
|
|
18988
|
+
logger$11.warn("[Call] enablePushToTalk: audio pipeline unavailable");
|
|
18989
|
+
return;
|
|
18990
|
+
}
|
|
18991
|
+
pipeline.setPTTActive(false);
|
|
18992
|
+
this._pushToTalkEnabled = true;
|
|
18993
|
+
}
|
|
18994
|
+
/** Disable push-to-talk; mic gain returns to the configured value. */
|
|
18995
|
+
disablePushToTalk() {
|
|
18996
|
+
this.vertoManager.localAudioPipeline?.setPTTActive(true);
|
|
18997
|
+
this._pushToTalkEnabled = false;
|
|
18998
|
+
}
|
|
18999
|
+
/**
|
|
19000
|
+
* While push-to-talk is enabled, sets the talk state. `true` = transmitting,
|
|
19001
|
+
* `false` = silent. No-op if push-to-talk has not been enabled.
|
|
19002
|
+
*/
|
|
19003
|
+
setPushToTalkActive(active) {
|
|
19004
|
+
if (!this._pushToTalkEnabled) return;
|
|
19005
|
+
this.vertoManager.localAudioPipeline?.setPTTActive(active);
|
|
19006
|
+
}
|
|
19007
|
+
/**
|
|
19008
|
+
* Toggle echo cancellation on the local mic at runtime. Applied via
|
|
19009
|
+
* `track.applyConstraints`; browsers that don't honour runtime constraints
|
|
19010
|
+
* (notably iOS Safari) fall back to re-acquiring the track with the new
|
|
19011
|
+
* constraint set and plumbing the replacement through the local audio
|
|
19012
|
+
* pipeline if one is active.
|
|
19013
|
+
*/
|
|
19014
|
+
async setEchoCancellation(enabled) {
|
|
19015
|
+
await this.vertoManager.updateMediaConstraints({ audio: { echoCancellation: enabled } });
|
|
19016
|
+
}
|
|
19017
|
+
/** Toggle browser noise suppression on the local mic at runtime. */
|
|
19018
|
+
async setNoiseSuppression(enabled) {
|
|
19019
|
+
await this.vertoManager.updateMediaConstraints({ audio: { noiseSuppression: enabled } });
|
|
19020
|
+
}
|
|
19021
|
+
/** Toggle browser automatic gain control on the local mic at runtime. */
|
|
19022
|
+
async setAutoGainControl(enabled) {
|
|
19023
|
+
await this.vertoManager.updateMediaConstraints({ audio: { autoGainControl: enabled } });
|
|
19024
|
+
}
|
|
19025
|
+
/**
|
|
19026
|
+
* Observable of the aggregate remote audio level, 0..1 RMS. The server
|
|
19027
|
+
* delivers a single mixed audio stream for all remote participants — this
|
|
19028
|
+
* meter reports that mix. Per-participant audio is not available client-side.
|
|
19029
|
+
*
|
|
19030
|
+
* Engages a shared AudioContext on first subscription (cheap — one
|
|
19031
|
+
* AnalyserNode, no GainNode, no destination) so it does not affect the
|
|
19032
|
+
* caller's audio element playback.
|
|
19033
|
+
*/
|
|
19034
|
+
get remoteAudioLevel$() {
|
|
19035
|
+
return this.publicCachedObservable("remoteAudioLevel$", () => {
|
|
19036
|
+
this._remoteAudioMeter ??= new RemoteAudioMeter();
|
|
19037
|
+
const meter = this._remoteAudioMeter;
|
|
19038
|
+
this.subscribeTo(this.vertoManager.remoteStream$, (stream) => {
|
|
19039
|
+
meter.setStream(stream);
|
|
19040
|
+
});
|
|
19041
|
+
return meter.level$.pipe((0, import_cjs$11.takeUntil)(this._destroyed$), (0, import_cjs$11.share)());
|
|
19042
|
+
});
|
|
19043
|
+
}
|
|
18497
19044
|
/** Destroys the call, releasing all resources and subscriptions. */
|
|
18498
19045
|
destroy() {
|
|
18499
19046
|
if (this._status$.value === "destroyed") return;
|
|
18500
19047
|
this._status$.next("destroyed");
|
|
18501
19048
|
this.stopResilienceSubsystems();
|
|
19049
|
+
this._remoteAudioMeter?.destroy();
|
|
19050
|
+
this._remoteAudioMeter = null;
|
|
18502
19051
|
this.vertoManager.destroy();
|
|
18503
19052
|
this.callEventsManager.destroy();
|
|
18504
19053
|
super.destroy();
|
|
18505
19054
|
}
|
|
18506
19055
|
/**
|
|
18507
19056
|
* @internal Send a verto.subscribe message to add an event type to the
|
|
18508
|
-
* server's subscription list for this call.
|
|
18509
|
-
*
|
|
19057
|
+
* server's subscription list for this call. Returns the underlying RPC
|
|
19058
|
+
* promise so callers can decide whether to cache the observable on success
|
|
19059
|
+
* or retry on failure.
|
|
18510
19060
|
*/
|
|
18511
|
-
_sendVertoSubscribe(eventType) {
|
|
18512
|
-
|
|
18513
|
-
|
|
18514
|
-
|
|
18515
|
-
|
|
18516
|
-
|
|
18517
|
-
|
|
18518
|
-
|
|
18519
|
-
|
|
18520
|
-
|
|
18521
|
-
|
|
18522
|
-
this.clientSession.execute(WebrtcVerto(params)).catch((error) => {
|
|
18523
|
-
logger$11.warn(`[Call] verto.subscribe for '${eventType}' failed (non-fatal):`, error);
|
|
18524
|
-
});
|
|
18525
|
-
} catch (error) {
|
|
18526
|
-
logger$11.warn(`[Call] Failed to send verto.subscribe for '${eventType}':`, error);
|
|
18527
|
-
}
|
|
19061
|
+
async _sendVertoSubscribe(eventType) {
|
|
19062
|
+
const message = VertoSubscribe({
|
|
19063
|
+
sessid: this.id,
|
|
19064
|
+
eventChannel: [eventType]
|
|
19065
|
+
});
|
|
19066
|
+
const params = {
|
|
19067
|
+
callID: this.id,
|
|
19068
|
+
node_id: this.vertoManager.nodeId ?? "",
|
|
19069
|
+
message
|
|
19070
|
+
};
|
|
19071
|
+
await this.clientSession.execute(WebrtcVerto(params));
|
|
18528
19072
|
}
|
|
18529
19073
|
};
|
|
18530
19074
|
|
|
@@ -18541,11 +19085,21 @@ function inferCallErrorKind(error) {
|
|
|
18541
19085
|
if (error instanceof WebSocketConnectionError || error instanceof TransportConnectionError) return "network";
|
|
18542
19086
|
return "internal";
|
|
18543
19087
|
}
|
|
19088
|
+
/** JSON-RPC error codes that ClientSessionManager treats as recoverable at the
|
|
19089
|
+
* session level. Surfacing one of these against an in-flight call should not
|
|
19090
|
+
* destroy the call, because the session will reauthenticate and any pending
|
|
19091
|
+
* RPC can then be retried. */
|
|
19092
|
+
const RECOVERABLE_RPC_CODES = new Set([
|
|
19093
|
+
RPC_ERROR_REQUESTER_VALIDATION_FAILED,
|
|
19094
|
+
RPC_ERROR_AUTHENTICATION_FAILED,
|
|
19095
|
+
RPC_ERROR_INVALID_PARAMS
|
|
19096
|
+
]);
|
|
18544
19097
|
/** Determines whether an error should be fatal (destroy the call). */
|
|
18545
19098
|
function isFatalError(error) {
|
|
18546
19099
|
if (error instanceof VertoPongError) return false;
|
|
18547
19100
|
if (error instanceof MediaTrackError) return false;
|
|
18548
19101
|
if (error instanceof RPCTimeoutError) return false;
|
|
19102
|
+
if (error instanceof JSONRPCError && RECOVERABLE_RPC_CODES.has(error.code)) return false;
|
|
18549
19103
|
return true;
|
|
18550
19104
|
}
|
|
18551
19105
|
/**
|
|
@@ -18983,10 +19537,10 @@ var PendingRPC = class PendingRPC {
|
|
|
18983
19537
|
}
|
|
18984
19538
|
let isSettled = false;
|
|
18985
19539
|
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) => {
|
|
18986
|
-
const timer$
|
|
19540
|
+
const timer$4 = setTimeout(() => {
|
|
18987
19541
|
subscriber.error(new RPCTimeoutError(request.id, timeoutMs));
|
|
18988
19542
|
}, timeoutMs);
|
|
18989
|
-
return () => clearTimeout(timer$
|
|
19543
|
+
return () => clearTimeout(timer$4);
|
|
18990
19544
|
}), signal ? new import_cjs$8.Observable((subscriber) => {
|
|
18991
19545
|
const abortHandler = () => {
|
|
18992
19546
|
subscriber.error(new DOMException("The operation was aborted", "AbortError"));
|
|
@@ -19052,7 +19606,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19052
19606
|
this.attachManager = attachManager;
|
|
19053
19607
|
this.dpopManager = dpopManager;
|
|
19054
19608
|
this.callCreateTimeout = 6e3;
|
|
19055
|
-
this.agent = `signalwire-
|
|
19609
|
+
this.agent = `signalwire-js/4.0.0`;
|
|
19056
19610
|
this.eventAcks = true;
|
|
19057
19611
|
this.authorizationState$ = this.createReplaySubject(1);
|
|
19058
19612
|
this.connectVersion = {
|
|
@@ -19064,7 +19618,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19064
19618
|
this._errors$ = this.createReplaySubject(1);
|
|
19065
19619
|
this._authState$ = this.createBehaviorSubject({ kind: "unauthenticated" });
|
|
19066
19620
|
this._wasClientBound = false;
|
|
19067
|
-
this.
|
|
19621
|
+
this._userInfo$ = this.createBehaviorSubject(null);
|
|
19068
19622
|
this._calls$ = this.createBehaviorSubject({});
|
|
19069
19623
|
this._iceServers$ = this.createBehaviorSubject([]);
|
|
19070
19624
|
attachManager.setSession(this);
|
|
@@ -19077,11 +19631,11 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19077
19631
|
get incomingCalls() {
|
|
19078
19632
|
return Object.values(this._calls$.value).filter((call) => call.direction === "inbound");
|
|
19079
19633
|
}
|
|
19080
|
-
get
|
|
19081
|
-
return this.
|
|
19634
|
+
get userInfo$() {
|
|
19635
|
+
return this._userInfo$.asObservable();
|
|
19082
19636
|
}
|
|
19083
|
-
get
|
|
19084
|
-
return this.
|
|
19637
|
+
get userInfo() {
|
|
19638
|
+
return this._userInfo$.value;
|
|
19085
19639
|
}
|
|
19086
19640
|
get calls$() {
|
|
19087
19641
|
return this.cachedObservable("calls$", () => this._calls$.pipe((0, import_cjs$7.map)((calls) => Object.values(calls))));
|
|
@@ -19386,7 +19940,6 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19386
19940
|
displayDirection: invite.display_direction,
|
|
19387
19941
|
userVariables: invite.userVariables
|
|
19388
19942
|
});
|
|
19389
|
-
await (0, import_cjs$7.firstValueFrom)(callSession.status$);
|
|
19390
19943
|
this._calls$.next({
|
|
19391
19944
|
[`${callSession.id}`]: callSession,
|
|
19392
19945
|
...this._calls$.value
|
|
@@ -19407,7 +19960,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19407
19960
|
logger$8.debug(`[Session] Verto attach for existing call ${callID}, deferring to per-call handler`);
|
|
19408
19961
|
return;
|
|
19409
19962
|
}
|
|
19410
|
-
const storedOptions = this.attachManager.consumePendingAttachment(callID);
|
|
19963
|
+
const storedOptions = await this.attachManager.consumePendingAttachment(callID);
|
|
19411
19964
|
logger$8.debug(`[Session] Creating reattached call for callID: ${callID}`);
|
|
19412
19965
|
const callSession = await this.createCall({
|
|
19413
19966
|
nodeId: attach.node_id,
|
|
@@ -19419,7 +19972,6 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19419
19972
|
reattach: true,
|
|
19420
19973
|
...storedOptions
|
|
19421
19974
|
});
|
|
19422
|
-
await (0, import_cjs$7.firstValueFrom)(callSession.status$);
|
|
19423
19975
|
this._calls$.next({
|
|
19424
19976
|
[`${callSession.id}`]: callSession,
|
|
19425
19977
|
...this._calls$.value
|
|
@@ -19529,22 +20081,22 @@ var ConversationMessageCollection = class extends EntityCollection {
|
|
|
19529
20081
|
}
|
|
19530
20082
|
};
|
|
19531
20083
|
var ConversationsManager = class {
|
|
19532
|
-
constructor(clientSession, http,
|
|
20084
|
+
constructor(clientSession, http, getUserAddressId, onError) {
|
|
19533
20085
|
this.clientSession = clientSession;
|
|
19534
20086
|
this.http = http;
|
|
19535
|
-
this.
|
|
20087
|
+
this.getUserAddressId = getUserAddressId;
|
|
19536
20088
|
this.onError = onError;
|
|
19537
20089
|
this.groupIds = /* @__PURE__ */ new Map();
|
|
19538
20090
|
}
|
|
19539
20091
|
async join(addressId) {
|
|
19540
|
-
const
|
|
20092
|
+
const userFromAddressId = this.getUserAddressId();
|
|
19541
20093
|
try {
|
|
19542
20094
|
const response = await this.http.request({
|
|
19543
20095
|
...POST_PARAMS,
|
|
19544
20096
|
url: `/api/fabric/conversations/join`,
|
|
19545
20097
|
body: JSON.stringify({
|
|
19546
|
-
from_fabric_address_id:
|
|
19547
|
-
fabric_address_ids: [addressId,
|
|
20098
|
+
from_fabric_address_id: userFromAddressId,
|
|
20099
|
+
fabric_address_ids: [addressId, userFromAddressId]
|
|
19548
20100
|
})
|
|
19549
20101
|
});
|
|
19550
20102
|
if (response.ok && !!response.body) {
|
|
@@ -19566,14 +20118,14 @@ var ConversationsManager = class {
|
|
|
19566
20118
|
}
|
|
19567
20119
|
async sendText(text, destinationAddressId) {
|
|
19568
20120
|
const groupId = this.groupIds.get(destinationAddressId) ?? await this.join(destinationAddressId);
|
|
19569
|
-
const
|
|
20121
|
+
const userFromAddressId = this.getUserAddressId();
|
|
19570
20122
|
try {
|
|
19571
20123
|
if ((await this.http.request({
|
|
19572
20124
|
...POST_PARAMS,
|
|
19573
20125
|
url: "/api/fabric/messages",
|
|
19574
20126
|
body: JSON.stringify({
|
|
19575
20127
|
group_id: groupId,
|
|
19576
|
-
from_fabric_address_id:
|
|
20128
|
+
from_fabric_address_id: userFromAddressId,
|
|
19577
20129
|
text
|
|
19578
20130
|
})
|
|
19579
20131
|
})).ok) return;
|
|
@@ -19646,17 +20198,17 @@ var DeviceTokenManager = class extends Destroyable {
|
|
|
19646
20198
|
return this._effectiveExpireIn;
|
|
19647
20199
|
}
|
|
19648
20200
|
/**
|
|
19649
|
-
* Activates the Client Bound SAT flow when the
|
|
20201
|
+
* Activates the Client Bound SAT flow when the user's token has
|
|
19650
20202
|
* `sat:refresh` scope.
|
|
19651
20203
|
*
|
|
19652
20204
|
* Steps:
|
|
19653
|
-
* 1. Check
|
|
20205
|
+
* 1. Check user's `sat_claims` for `sat:refresh` scope
|
|
19654
20206
|
* 2. Call `/api/fabric/subscriber/devices/token` with a DPoP proof
|
|
19655
20207
|
* 3. Reauthenticate the session with the Client Bound SAT + DPoP proof
|
|
19656
20208
|
* 4. Emit token to trigger the reactive refresh pipeline
|
|
19657
20209
|
*/
|
|
19658
|
-
async activate(
|
|
19659
|
-
const { satClaims } =
|
|
20210
|
+
async activate(user, session, updateCredential) {
|
|
20211
|
+
const { satClaims } = user;
|
|
19660
20212
|
if (!satClaims?.scope?.includes(SAT_REFRESH_SCOPE)) {
|
|
19661
20213
|
logger$6.debug("[DeviceToken] No sat:refresh scope, skipping Client Bound SAT activation");
|
|
19662
20214
|
return;
|
|
@@ -19939,9 +20491,9 @@ const isEmptyArray = (a) => {
|
|
|
19939
20491
|
};
|
|
19940
20492
|
|
|
19941
20493
|
//#endregion
|
|
19942
|
-
//#region src/utils/
|
|
20494
|
+
//#region src/utils/warmup.ts
|
|
19943
20495
|
var import_cjs$4 = require_cjs();
|
|
19944
|
-
const
|
|
20496
|
+
const warmup = (observable) => {
|
|
19945
20497
|
observable.pipe((0, import_cjs$4.take)(1)).subscribe();
|
|
19946
20498
|
};
|
|
19947
20499
|
|
|
@@ -19990,7 +20542,7 @@ var DirectoryManager = class extends Destroyable {
|
|
|
19990
20542
|
return address;
|
|
19991
20543
|
}));
|
|
19992
20544
|
if (observable) {
|
|
19993
|
-
|
|
20545
|
+
warmup(observable);
|
|
19994
20546
|
this._observableRegistry.set(id, observable);
|
|
19995
20547
|
}
|
|
19996
20548
|
this._addressesInstances.set(id, address);
|
|
@@ -20142,10 +20694,9 @@ var WebSocketController = class WebSocketController extends Destroyable {
|
|
|
20142
20694
|
else this._status$.next("disconnected");
|
|
20143
20695
|
}
|
|
20144
20696
|
reconnect() {
|
|
20145
|
-
|
|
20146
|
-
|
|
20147
|
-
|
|
20148
|
-
} else this._status$.next("disconnected");
|
|
20697
|
+
this.shouldReconnect = true;
|
|
20698
|
+
this._status$.next("reconnecting");
|
|
20699
|
+
this.scheduleReconnection();
|
|
20149
20700
|
}
|
|
20150
20701
|
send(data) {
|
|
20151
20702
|
if (this._status$.value === "connected" && this.socket?.readyState === 1) {
|
|
@@ -20504,7 +21055,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20504
21055
|
constructor(credentialProvider, options = {}) {
|
|
20505
21056
|
super();
|
|
20506
21057
|
this.preferences = new ClientPreferences();
|
|
20507
|
-
this.
|
|
21058
|
+
this._user$ = this.createBehaviorSubject(void 0);
|
|
20508
21059
|
this._directory$ = this.createBehaviorSubject(void 0);
|
|
20509
21060
|
this._isConnected$ = this.createBehaviorSubject(false);
|
|
20510
21061
|
this._isRegistered$ = this.createBehaviorSubject(false);
|
|
@@ -20644,7 +21195,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20644
21195
|
if (this._deps.persistSession) this._deps.storage.setItem("sw:cached_credential", credential, "local");
|
|
20645
21196
|
}
|
|
20646
21197
|
async init() {
|
|
20647
|
-
this.
|
|
21198
|
+
this._user$.next(new User(this._deps.http));
|
|
20648
21199
|
if (!this._options.skipConnection) await this.connect();
|
|
20649
21200
|
if (!this._options.reconnectAttachedCalls && this._attachManager) await this._attachManager.flush();
|
|
20650
21201
|
if (!this._options.skipRegister) try {
|
|
@@ -20706,14 +21257,15 @@ var SignalWire = class extends Destroyable {
|
|
|
20706
21257
|
* `'reconnecting'`, `'disconnecting'`, or `'disconnected'`.
|
|
20707
21258
|
*/
|
|
20708
21259
|
async connect() {
|
|
21260
|
+
await this.teardownTransportAndSession();
|
|
20709
21261
|
try {
|
|
20710
|
-
const
|
|
20711
|
-
if (!
|
|
20712
|
-
if (!await (0, import_cjs$1.firstValueFrom)(
|
|
20713
|
-
this._deps.
|
|
21262
|
+
const user = this._user$.value;
|
|
21263
|
+
if (!user) throw new UnexpectedError("User not initialized before connect");
|
|
21264
|
+
if (!await (0, import_cjs$1.firstValueFrom)(user.fetched$)) throw new UnexpectedError("Failed to fetch user information - fetched$ emitted false");
|
|
21265
|
+
this._deps.user = user;
|
|
20714
21266
|
} catch (error) {
|
|
20715
|
-
logger$1.error(`[SignalWire] Failed to fetch
|
|
20716
|
-
throw new UnexpectedError("Error fetching
|
|
21267
|
+
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.`);
|
|
21268
|
+
throw new UnexpectedError("Error fetching user information", { cause: error });
|
|
20717
21269
|
}
|
|
20718
21270
|
const errorHandler = (error) => {
|
|
20719
21271
|
this._errors$.next(error);
|
|
@@ -20747,7 +21299,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20747
21299
|
logger$1.debug("[SignalWire] Developer refresh disabled — Client Bound SAT activation starting");
|
|
20748
21300
|
}
|
|
20749
21301
|
this._deviceTokenManager = new DeviceTokenManager(this._dpopManager, this._deps.http, (error) => this._errors$.next(error), () => this._deps.credential);
|
|
20750
|
-
await this._deviceTokenManager.activate(this._deps.
|
|
21302
|
+
await this._deviceTokenManager.activate(this._deps.user, this._clientSession, (cred) => {
|
|
20751
21303
|
this._deps.credential = {
|
|
20752
21304
|
...this._deps.credential,
|
|
20753
21305
|
...cred
|
|
@@ -20757,7 +21309,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20757
21309
|
this.subscribeTo(this._clientSession.authenticated$.pipe((0, import_cjs$1.skip)(1), (0, import_cjs$1.filter)(Boolean)), async () => {
|
|
20758
21310
|
try {
|
|
20759
21311
|
if (this._deviceTokenManager) {
|
|
20760
|
-
await this._deviceTokenManager.activate(this._deps.
|
|
21312
|
+
await this._deviceTokenManager.activate(this._deps.user, this._clientSession, (cred) => {
|
|
20761
21313
|
this._deps.credential = {
|
|
20762
21314
|
...this._deps.credential,
|
|
20763
21315
|
...cred
|
|
@@ -20770,15 +21322,15 @@ var SignalWire = class extends Destroyable {
|
|
|
20770
21322
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
20771
21323
|
}
|
|
20772
21324
|
try {
|
|
20773
|
-
logger$1.debug("[SignalWire] Re-registering
|
|
21325
|
+
logger$1.debug("[SignalWire] Re-registering user after reconnect");
|
|
20774
21326
|
await this.register();
|
|
20775
|
-
logger$1.debug("[SignalWire]
|
|
21327
|
+
logger$1.debug("[SignalWire] User re-registered successfully after reconnect");
|
|
20776
21328
|
} catch (error) {
|
|
20777
21329
|
logger$1.error("[SignalWire] Re-registration failed after reconnect:", error);
|
|
20778
21330
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
20779
21331
|
}
|
|
20780
21332
|
});
|
|
20781
|
-
const conversationManager = new ConversationsManager(this._clientSession, this._deps.http, () => this._deps.
|
|
21333
|
+
const conversationManager = new ConversationsManager(this._clientSession, this._deps.http, () => this._deps.getUserFromAddressId(), errorHandler);
|
|
20782
21334
|
const directory = new DirectoryManager(this._deps.http, this._clientSession, conversationManager, errorHandler);
|
|
20783
21335
|
this._directory$.next(directory);
|
|
20784
21336
|
this._clientSession.setDirectory(directory);
|
|
@@ -20789,22 +21341,22 @@ var SignalWire = class extends Destroyable {
|
|
|
20789
21341
|
});
|
|
20790
21342
|
}
|
|
20791
21343
|
/**
|
|
20792
|
-
* Observable that emits the {@link
|
|
21344
|
+
* Observable that emits the {@link User} profile once fetched,
|
|
20793
21345
|
* or `undefined` before authentication completes.
|
|
20794
21346
|
*
|
|
20795
21347
|
* @example
|
|
20796
21348
|
* ```ts
|
|
20797
|
-
* client.
|
|
20798
|
-
* if (
|
|
21349
|
+
* client.user$.subscribe(u => {
|
|
21350
|
+
* if (u) console.log('Logged in as', u.email);
|
|
20799
21351
|
* });
|
|
20800
21352
|
* ```
|
|
20801
21353
|
*/
|
|
20802
|
-
get
|
|
20803
|
-
return this.deferEmission(this.
|
|
21354
|
+
get user$() {
|
|
21355
|
+
return this.deferEmission(this._user$.asObservable());
|
|
20804
21356
|
}
|
|
20805
|
-
/** Current
|
|
20806
|
-
get
|
|
20807
|
-
return this.
|
|
21357
|
+
/** Current user snapshot, or `undefined` if not yet authenticated. */
|
|
21358
|
+
get user() {
|
|
21359
|
+
return this._user$.value;
|
|
20808
21360
|
}
|
|
20809
21361
|
/**
|
|
20810
21362
|
* Observable that emits the {@link Directory} instance once the client is connected,
|
|
@@ -20828,11 +21380,11 @@ var SignalWire = class extends Destroyable {
|
|
|
20828
21380
|
get directory() {
|
|
20829
21381
|
return this._directory$.value;
|
|
20830
21382
|
}
|
|
20831
|
-
/** Observable that emits when the
|
|
21383
|
+
/** Observable that emits when the user registration state changes. */
|
|
20832
21384
|
get isRegistered$() {
|
|
20833
21385
|
return this.deferEmission(this._isRegistered$.asObservable());
|
|
20834
21386
|
}
|
|
20835
|
-
/** Whether the
|
|
21387
|
+
/** Whether the user is currently registered. */
|
|
20836
21388
|
get isRegistered() {
|
|
20837
21389
|
return this._isRegistered$.value;
|
|
20838
21390
|
}
|
|
@@ -20937,15 +21489,35 @@ var SignalWire = class extends Destroyable {
|
|
|
20937
21489
|
this._refreshTimerId = void 0;
|
|
20938
21490
|
}
|
|
20939
21491
|
this._diagnosticsCollector?.record("connection", "disconnected");
|
|
20940
|
-
await this.
|
|
20941
|
-
this._clientSession.destroy();
|
|
21492
|
+
await this.teardownTransportAndSession();
|
|
20942
21493
|
this._isConnected$.next(false);
|
|
20943
21494
|
}
|
|
21495
|
+
/**
|
|
21496
|
+
* Tear down the current transport / session / attach manager. Safe to call
|
|
21497
|
+
* when nothing has been initialized yet (e.g. first connect()).
|
|
21498
|
+
*/
|
|
21499
|
+
async teardownTransportAndSession() {
|
|
21500
|
+
const session = this._clientSession;
|
|
21501
|
+
const transport = this._transport;
|
|
21502
|
+
if (session) {
|
|
21503
|
+
try {
|
|
21504
|
+
await session.disconnect();
|
|
21505
|
+
} catch (error) {
|
|
21506
|
+
logger$1.warn("[SignalWire] Error disconnecting previous session:", error);
|
|
21507
|
+
}
|
|
21508
|
+
session.destroy();
|
|
21509
|
+
}
|
|
21510
|
+
if (transport) transport.destroy();
|
|
21511
|
+
this._clientSession = void 0;
|
|
21512
|
+
this._publicSession = void 0;
|
|
21513
|
+
this._transport = void 0;
|
|
21514
|
+
this._attachManager = void 0;
|
|
21515
|
+
}
|
|
20944
21516
|
async waitAuthentication() {
|
|
20945
21517
|
await (0, import_cjs$1.firstValueFrom)(this.ready$.pipe((0, import_cjs$1.filter)((ready$1) => ready$1 === true)));
|
|
20946
21518
|
}
|
|
20947
21519
|
/**
|
|
20948
|
-
* Registers the
|
|
21520
|
+
* Registers the user as online to receive inbound calls and events.
|
|
20949
21521
|
*
|
|
20950
21522
|
* Waits for authentication to complete before sending the registration.
|
|
20951
21523
|
* If the initial attempt fails, reauthentication is attempted automatically.
|
|
@@ -20960,26 +21532,31 @@ var SignalWire = class extends Destroyable {
|
|
|
20960
21532
|
params: {}
|
|
20961
21533
|
}));
|
|
20962
21534
|
this._isRegistered$.next(true);
|
|
21535
|
+
return;
|
|
20963
21536
|
} catch (error) {
|
|
20964
|
-
|
|
20965
|
-
|
|
21537
|
+
if (!this._deps.credential.token) {
|
|
21538
|
+
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
21539
|
+
throw error;
|
|
21540
|
+
}
|
|
21541
|
+
logger$1.debug("[SignalWire] Failed to register user, trying reauthentication...");
|
|
21542
|
+
try {
|
|
21543
|
+
await this._clientSession.reauthenticate(this._deps.credential.token);
|
|
20966
21544
|
logger$1.debug("[SignalWire] Reauthentication successful, retrying register()");
|
|
20967
21545
|
await this._transport.execute(RPCExecute({
|
|
20968
21546
|
method: "subscriber.online",
|
|
20969
21547
|
params: {}
|
|
20970
21548
|
}));
|
|
20971
21549
|
this._isRegistered$.next(true);
|
|
20972
|
-
}
|
|
21550
|
+
} catch (reauthError) {
|
|
20973
21551
|
logger$1.error("[SignalWire] Reauthentication failed during register():", reauthError);
|
|
20974
|
-
const registerError = new InvalidCredentialsError("Failed to register
|
|
21552
|
+
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 }) });
|
|
20975
21553
|
this._errors$.next(registerError);
|
|
20976
|
-
|
|
20977
|
-
|
|
20978
|
-
throw error;
|
|
21554
|
+
throw registerError;
|
|
21555
|
+
}
|
|
20979
21556
|
}
|
|
20980
21557
|
}
|
|
20981
21558
|
/**
|
|
20982
|
-
* Unregisters the
|
|
21559
|
+
* Unregisters the user, going offline for inbound calls.
|
|
20983
21560
|
*
|
|
20984
21561
|
* The WebSocket connection remains open; use {@link disconnect} to fully close it.
|
|
20985
21562
|
*/
|
|
@@ -20991,7 +21568,7 @@ var SignalWire = class extends Destroyable {
|
|
|
20991
21568
|
}));
|
|
20992
21569
|
this._isRegistered$.next(false);
|
|
20993
21570
|
} catch (error) {
|
|
20994
|
-
logger$1.error("[SignalWire] Failed to unregister
|
|
21571
|
+
logger$1.error("[SignalWire] Failed to unregister user:", error);
|
|
20995
21572
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
20996
21573
|
throw error;
|
|
20997
21574
|
}
|
|
@@ -21131,6 +21708,36 @@ var SignalWire = class extends Destroyable {
|
|
|
21131
21708
|
selectAudioOutputDevice(device) {
|
|
21132
21709
|
this._deviceController.selectAudioOutputDevice(device);
|
|
21133
21710
|
}
|
|
21711
|
+
/**
|
|
21712
|
+
* Apply the currently selected audio output device to an HTMLMediaElement
|
|
21713
|
+
* (e.g. the `<audio>` or `<video>` element the consumer attached the
|
|
21714
|
+
* remote stream to). Uses `HTMLMediaElement.setSinkId` under the hood.
|
|
21715
|
+
* Returns a `Promise<boolean>`: `true` if the sink was applied,
|
|
21716
|
+
* `false` if the browser doesn't support `setSinkId` or no device is
|
|
21717
|
+
* selected.
|
|
21718
|
+
*
|
|
21719
|
+
* @example
|
|
21720
|
+
* ```ts
|
|
21721
|
+
* audioEl.srcObject = call.remoteStream;
|
|
21722
|
+
* await client.applySelectedAudioOutputDevice(audioEl);
|
|
21723
|
+
* ```
|
|
21724
|
+
*/
|
|
21725
|
+
async applySelectedAudioOutputDevice(element) {
|
|
21726
|
+
const device = this._deviceController.selectedAudioOutputDevice;
|
|
21727
|
+
if (!device?.deviceId) return false;
|
|
21728
|
+
const withSink = element;
|
|
21729
|
+
if (typeof withSink.setSinkId !== "function") {
|
|
21730
|
+
logger$1.warn("[SignalWire] setSinkId not supported on this element / browser");
|
|
21731
|
+
return false;
|
|
21732
|
+
}
|
|
21733
|
+
try {
|
|
21734
|
+
await withSink.setSinkId(device.deviceId);
|
|
21735
|
+
return true;
|
|
21736
|
+
} catch (error) {
|
|
21737
|
+
logger$1.warn("[SignalWire] Failed to apply audio output device:", error);
|
|
21738
|
+
return false;
|
|
21739
|
+
}
|
|
21740
|
+
}
|
|
21134
21741
|
/** Starts monitoring for media device changes (connect/disconnect). */
|
|
21135
21742
|
enableDeviceMonitoring() {
|
|
21136
21743
|
this._deviceController.enableDeviceMonitoring();
|
|
@@ -21311,6 +21918,7 @@ var EmbedTokenCredentialProvider = class {
|
|
|
21311
21918
|
try {
|
|
21312
21919
|
const response = await fetch(url, {
|
|
21313
21920
|
method: "POST",
|
|
21921
|
+
headers: { "Content-Type": "application/json" },
|
|
21314
21922
|
body: JSON.stringify({ token: this.embedToken }),
|
|
21315
21923
|
signal: controller.signal
|
|
21316
21924
|
});
|
|
@@ -21435,5 +22043,5 @@ emitReadyEvent();
|
|
|
21435
22043
|
if (typeof process === "undefined") globalThis.process = { env: { NODE_ENV: "production" } };
|
|
21436
22044
|
|
|
21437
22045
|
//#endregion
|
|
21438
|
-
export { Address, CallCreateError, ClientPreferences, CollectionFetchError, DPoPInitError, DeviceTokenError, InvalidCredentialsError, MediaTrackError, MessageParseError, OverconstrainedFallbackError, Participant, PreflightError, RecoveryError, SelfCapabilities, SelfParticipant, SignalWire, StaticCredentialProvider,
|
|
22046
|
+
export { Address, CallCreateError, ClientPreferences, CollectionFetchError, DPoPInitError, DeviceTokenError, EmbedTokenCredentialProvider, InvalidCredentialsError, MediaTrackError, MessageParseError, OverconstrainedFallbackError, Participant, PreflightError, RecoveryError, SelfCapabilities, SelfParticipant, SignalWire, StaticCredentialProvider, TokenRefreshError, UnexpectedError, User, VertoPongError, WebRTCCall, embeddableCall, getLogger, isSelfParticipant, ready, setDebugOptions, setLogLevel, setLogger, version };
|
|
21439
22047
|
//# sourceMappingURL=browser.mjs.map
|