@signalwire/js 4.0.0-beta.7 → 4.0.0-beta.9
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/base-CQPEW1lJ.d.mts +31 -0
- package/dist/base-CQPEW1lJ.d.mts.map +1 -0
- package/dist/base-Cif20s3C.d.cts +31 -0
- package/dist/base-Cif20s3C.d.cts.map +1 -0
- package/dist/browser.mjs +502 -173
- package/dist/browser.mjs.map +1 -1
- package/dist/browser.umd.js +502 -173
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +485 -158
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +333 -153
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +333 -153
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +486 -159
- package/dist/index.mjs.map +1 -1
- package/dist/operators/index.cjs +1 -1
- package/dist/operators/index.d.cts +1 -1
- package/dist/operators/index.d.mts +1 -1
- package/dist/operators/index.mjs +1 -1
- package/dist/{operators-DT4UB24-.cjs → operators-mm21prWr.cjs} +5 -3
- package/dist/operators-mm21prWr.cjs.map +1 -0
- package/dist/{operators-BHQMSEzq.mjs → operators-uT_fb8ba.mjs} +5 -3
- package/dist/operators-uT_fb8ba.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/base-A5AZTrAd.d.cts +0 -23
- package/dist/base-A5AZTrAd.d.cts.map +0 -1
- package/dist/base-aVtoG8Wk.d.mts +0 -23
- package/dist/base-aVtoG8Wk.d.mts.map +0 -1
- package/dist/operators-BHQMSEzq.mjs.map +0 -1
- package/dist/operators-DT4UB24-.cjs.map +0 -1
package/dist/browser.mjs
CHANGED
|
@@ -2879,7 +2879,7 @@ var require_observeOn = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
2879
2879
|
var executeSchedule_1$7 = require_executeSchedule();
|
|
2880
2880
|
var lift_1$67 = require_lift();
|
|
2881
2881
|
var OperatorSubscriber_1$56 = require_OperatorSubscriber();
|
|
2882
|
-
function observeOn(scheduler, delay$1) {
|
|
2882
|
+
function observeOn$1(scheduler, delay$1) {
|
|
2883
2883
|
if (delay$1 === void 0) delay$1 = 0;
|
|
2884
2884
|
return lift_1$67.operate(function(source, subscriber) {
|
|
2885
2885
|
source.subscribe(OperatorSubscriber_1$56.createOperatorSubscriber(subscriber, function(value) {
|
|
@@ -2897,7 +2897,7 @@ var require_observeOn = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
2897
2897
|
}));
|
|
2898
2898
|
});
|
|
2899
2899
|
}
|
|
2900
|
-
exports.observeOn = observeOn;
|
|
2900
|
+
exports.observeOn = observeOn$1;
|
|
2901
2901
|
}));
|
|
2902
2902
|
|
|
2903
2903
|
//#endregion
|
|
@@ -3107,7 +3107,7 @@ var require_throwError = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3107
3107
|
exports.throwError = void 0;
|
|
3108
3108
|
var Observable_1$18 = require_Observable();
|
|
3109
3109
|
var isFunction_1$14 = require_isFunction();
|
|
3110
|
-
function throwError(errorOrErrorFactory, scheduler) {
|
|
3110
|
+
function throwError$1(errorOrErrorFactory, scheduler) {
|
|
3111
3111
|
var errorFactory = isFunction_1$14.isFunction(errorOrErrorFactory) ? errorOrErrorFactory : function() {
|
|
3112
3112
|
return errorOrErrorFactory;
|
|
3113
3113
|
};
|
|
@@ -3118,7 +3118,7 @@ var require_throwError = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
3118
3118
|
return scheduler.schedule(init, 0, subscriber);
|
|
3119
3119
|
} : init);
|
|
3120
3120
|
}
|
|
3121
|
-
exports.throwError = throwError;
|
|
3121
|
+
exports.throwError = throwError$1;
|
|
3122
3122
|
}));
|
|
3123
3123
|
|
|
3124
3124
|
//#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$4() {
|
|
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$4;
|
|
4337
4337
|
function raceInit(sources) {
|
|
4338
4338
|
return function(subscriber) {
|
|
4339
4339
|
var subscriptions = [];
|
|
@@ -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$6(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$6;
|
|
5490
5490
|
function defaultCompare(a, b) {
|
|
5491
5491
|
return a === b;
|
|
5492
5492
|
}
|
|
@@ -6915,7 +6915,7 @@ var require_startWith = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
6915
6915
|
var concat_1$2 = require_concat$1();
|
|
6916
6916
|
var args_1$2 = require_args();
|
|
6917
6917
|
var lift_1$14 = require_lift();
|
|
6918
|
-
function startWith() {
|
|
6918
|
+
function startWith$1() {
|
|
6919
6919
|
var values = [];
|
|
6920
6920
|
for (var _i = 0; _i < arguments.length; _i++) values[_i] = arguments[_i];
|
|
6921
6921
|
var scheduler = args_1$2.popScheduler(values);
|
|
@@ -6923,7 +6923,7 @@ var require_startWith = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
6923
6923
|
(scheduler ? concat_1$2.concat(values, source, scheduler) : concat_1$2.concat(values, source)).subscribe(subscriber);
|
|
6924
6924
|
});
|
|
6925
6925
|
}
|
|
6926
|
-
exports.startWith = startWith;
|
|
6926
|
+
exports.startWith = startWith$1;
|
|
6927
6927
|
}));
|
|
6928
6928
|
|
|
6929
6929
|
//#endregion
|
|
@@ -6934,7 +6934,7 @@ var require_switchMap = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
6934
6934
|
var innerFrom_1$6 = require_innerFrom();
|
|
6935
6935
|
var lift_1$13 = require_lift();
|
|
6936
6936
|
var OperatorSubscriber_1$11 = require_OperatorSubscriber();
|
|
6937
|
-
function switchMap$
|
|
6937
|
+
function switchMap$4(project, resultSelector) {
|
|
6938
6938
|
return lift_1$13.operate(function(source, subscriber) {
|
|
6939
6939
|
var innerSubscriber = null;
|
|
6940
6940
|
var index = 0;
|
|
@@ -6958,7 +6958,7 @@ var require_switchMap = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
6958
6958
|
}));
|
|
6959
6959
|
});
|
|
6960
6960
|
}
|
|
6961
|
-
exports.switchMap = switchMap$
|
|
6961
|
+
exports.switchMap = switchMap$4;
|
|
6962
6962
|
}));
|
|
6963
6963
|
|
|
6964
6964
|
//#endregion
|
|
@@ -8956,6 +8956,40 @@ var Destroyable = class {
|
|
|
8956
8956
|
}
|
|
8957
8957
|
return cached;
|
|
8958
8958
|
}
|
|
8959
|
+
/**
|
|
8960
|
+
* Like `cachedObservable`, but defers emissions to the microtask queue
|
|
8961
|
+
* via `observeOn(asapScheduler)`.
|
|
8962
|
+
*
|
|
8963
|
+
* Use ONLY for public-facing observable getters that external consumers
|
|
8964
|
+
* subscribe to. Prevents a class of bugs where `BehaviorSubject` or
|
|
8965
|
+
* `ReplaySubject` replays synchronously during `subscribe()`, before
|
|
8966
|
+
* the subscription variable is assigned in the caller's scope.
|
|
8967
|
+
*
|
|
8968
|
+
* Do NOT use for observables consumed internally by the SDK — internal
|
|
8969
|
+
* code using `subscribeTo()`, `firstValueFrom()`, or `withLatestFrom()`
|
|
8970
|
+
* depends on synchronous emission delivery.
|
|
8971
|
+
*/
|
|
8972
|
+
publicCachedObservable(key, factory) {
|
|
8973
|
+
const publicKey = `public:${key}`;
|
|
8974
|
+
this._observableCache ??= /* @__PURE__ */ new Map();
|
|
8975
|
+
let cached = this._observableCache.get(publicKey);
|
|
8976
|
+
if (!cached) {
|
|
8977
|
+
cached = factory().pipe((0, import_cjs$22.observeOn)(import_cjs$22.asapScheduler));
|
|
8978
|
+
this._observableCache.set(publicKey, cached);
|
|
8979
|
+
}
|
|
8980
|
+
return cached;
|
|
8981
|
+
}
|
|
8982
|
+
/**
|
|
8983
|
+
* Wraps an observable so emissions are deferred to the microtask queue.
|
|
8984
|
+
*
|
|
8985
|
+
* Use ONLY for public-facing getters that expose a subject via
|
|
8986
|
+
* `.asObservable()` without going through `cachedObservable`.
|
|
8987
|
+
*
|
|
8988
|
+
* Do NOT use for observables consumed internally by the SDK.
|
|
8989
|
+
*/
|
|
8990
|
+
deferEmission(observable) {
|
|
8991
|
+
return observable.pipe((0, import_cjs$22.observeOn)(import_cjs$22.asapScheduler));
|
|
8992
|
+
}
|
|
8959
8993
|
subscribeTo(observable, observerOrNext) {
|
|
8960
8994
|
const subscription = observable.subscribe(observerOrNext);
|
|
8961
8995
|
this.subscriptions.push(subscription);
|
|
@@ -9104,21 +9138,23 @@ var DependencyError = class extends Error {
|
|
|
9104
9138
|
}
|
|
9105
9139
|
};
|
|
9106
9140
|
var CallCreateError = class extends Error {
|
|
9107
|
-
constructor(message, error = null, options) {
|
|
9141
|
+
constructor(message, error = null, direction = "outbound", options) {
|
|
9108
9142
|
super(message, {
|
|
9109
9143
|
...options,
|
|
9110
9144
|
cause: options?.cause ?? (error instanceof Error ? error : void 0)
|
|
9111
9145
|
});
|
|
9112
9146
|
this.message = message;
|
|
9113
9147
|
this.error = error;
|
|
9148
|
+
this.direction = direction;
|
|
9114
9149
|
this.name = "CallCreateError";
|
|
9115
9150
|
}
|
|
9116
9151
|
};
|
|
9117
9152
|
var JSONRPCError = class extends Error {
|
|
9118
|
-
constructor(code, message, data, options) {
|
|
9153
|
+
constructor(code, message, data, options, requestId) {
|
|
9119
9154
|
super(message, options);
|
|
9120
9155
|
this.code = code;
|
|
9121
9156
|
this.data = data;
|
|
9157
|
+
this.requestId = requestId;
|
|
9122
9158
|
this.name = "JSONRPCError";
|
|
9123
9159
|
}
|
|
9124
9160
|
};
|
|
@@ -9660,7 +9696,7 @@ var PreferencesContainer = class PreferencesContainer {
|
|
|
9660
9696
|
skipDeviceMonitoring: false,
|
|
9661
9697
|
savePreferences: false
|
|
9662
9698
|
};
|
|
9663
|
-
this.receiveVideo =
|
|
9699
|
+
this.receiveVideo = false;
|
|
9664
9700
|
this.receiveAudio = true;
|
|
9665
9701
|
this.preferredAudioInput = null;
|
|
9666
9702
|
this.preferredAudioOutput = null;
|
|
@@ -9973,7 +10009,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
9973
10009
|
};
|
|
9974
10010
|
this._devicesState$ = this.createBehaviorSubject(initialDevicesState);
|
|
9975
10011
|
this._selectedDevicesState$ = this.createBehaviorSubject(initialSelectedDevicesState);
|
|
9976
|
-
this._errors$ = this.
|
|
10012
|
+
this._errors$ = this.createReplaySubject(1);
|
|
9977
10013
|
this.init();
|
|
9978
10014
|
}
|
|
9979
10015
|
get selectedAudioInputDeviceConstraints() {
|
|
@@ -10500,7 +10536,7 @@ const RPCExecute = ({ method, params }) => {
|
|
|
10500
10536
|
|
|
10501
10537
|
//#endregion
|
|
10502
10538
|
//#region src/core/RPCMessages/VertoMessages.ts
|
|
10503
|
-
const
|
|
10539
|
+
const SDK_TO_VERTO_FIELD_MAP = {
|
|
10504
10540
|
id: "callID",
|
|
10505
10541
|
destinationNumber: "destination_number",
|
|
10506
10542
|
remoteCallerName: "remote_caller_id_name",
|
|
@@ -10509,19 +10545,31 @@ const tmpMap = {
|
|
|
10509
10545
|
callerNumber: "caller_id_number",
|
|
10510
10546
|
fromCallAddressId: "from_fabric_address_id"
|
|
10511
10547
|
};
|
|
10548
|
+
const EXCLUDED_DIALOG_PARAMS = new Set([
|
|
10549
|
+
"remoteSdp",
|
|
10550
|
+
"localStream",
|
|
10551
|
+
"remoteStream"
|
|
10552
|
+
]);
|
|
10512
10553
|
/**
|
|
10513
|
-
* Translate SDK fields into verto variables
|
|
10554
|
+
* Translate SDK fields into verto variables.
|
|
10555
|
+
* Returns a new object — the input is never mutated.
|
|
10514
10556
|
*/
|
|
10557
|
+
/** @internal Exported for testing only. */
|
|
10515
10558
|
const filterVertoParams = (params) => {
|
|
10516
|
-
if (Object.prototype.hasOwnProperty.call(params, "dialogParams"))
|
|
10517
|
-
|
|
10518
|
-
|
|
10519
|
-
|
|
10520
|
-
|
|
10521
|
-
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
|
|
10559
|
+
if (!Object.prototype.hasOwnProperty.call(params, "dialogParams")) return params;
|
|
10560
|
+
const sourceDialogParams = params.dialogParams;
|
|
10561
|
+
const filteredDialogParams = Object.entries(sourceDialogParams).reduce((acc, [key, value]) => {
|
|
10562
|
+
if (EXCLUDED_DIALOG_PARAMS.has(key)) return acc;
|
|
10563
|
+
const mappedKey = SDK_TO_VERTO_FIELD_MAP[key] ?? key;
|
|
10564
|
+
return {
|
|
10565
|
+
...acc,
|
|
10566
|
+
[mappedKey]: value
|
|
10567
|
+
};
|
|
10568
|
+
}, {});
|
|
10569
|
+
return {
|
|
10570
|
+
...params,
|
|
10571
|
+
dialogParams: filteredDialogParams
|
|
10572
|
+
};
|
|
10525
10573
|
};
|
|
10526
10574
|
const buildVertoRPCMessage = (method) => {
|
|
10527
10575
|
return (params = {}) => {
|
|
@@ -10632,17 +10680,21 @@ var AttachManager = class {
|
|
|
10632
10680
|
buildCallOptions(attachment) {
|
|
10633
10681
|
const { audio: audioDirection, video: videoDirection } = attachment.mediaDirections;
|
|
10634
10682
|
const { audioInputDevice, videoInputDevice } = attachment;
|
|
10683
|
+
const receiveAudio = audioDirection.includes("recv");
|
|
10684
|
+
const receiveVideo = videoDirection.includes("recv");
|
|
10685
|
+
const sendAudio = audioDirection.includes("send");
|
|
10686
|
+
const sendVideo = videoDirection.includes("send");
|
|
10635
10687
|
return {
|
|
10636
|
-
receiveAudio
|
|
10637
|
-
receiveVideo
|
|
10638
|
-
inputAudioDeviceConstraints: {
|
|
10639
|
-
audio:
|
|
10688
|
+
receiveAudio,
|
|
10689
|
+
receiveVideo,
|
|
10690
|
+
inputAudioDeviceConstraints: sendAudio ? {
|
|
10691
|
+
audio: true,
|
|
10640
10692
|
...this.deviceController.deviceInfoToConstraints(audioInputDevice)
|
|
10641
|
-
},
|
|
10642
|
-
inputVideoDeviceConstraints: {
|
|
10643
|
-
video:
|
|
10693
|
+
} : void 0,
|
|
10694
|
+
inputVideoDeviceConstraints: sendVideo ? {
|
|
10695
|
+
video: true,
|
|
10644
10696
|
...this.deviceController.deviceInfoToConstraints(videoInputDevice)
|
|
10645
|
-
},
|
|
10697
|
+
} : void 0,
|
|
10646
10698
|
reattach: true
|
|
10647
10699
|
};
|
|
10648
10700
|
}
|
|
@@ -10703,12 +10755,12 @@ var require_race = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
10703
10755
|
exports.race = void 0;
|
|
10704
10756
|
var argsOrArgArray_1 = require_argsOrArgArray();
|
|
10705
10757
|
var raceWith_1$1 = require_raceWith();
|
|
10706
|
-
function race$
|
|
10758
|
+
function race$3() {
|
|
10707
10759
|
var args = [];
|
|
10708
10760
|
for (var _i = 0; _i < arguments.length; _i++) args[_i] = arguments[_i];
|
|
10709
10761
|
return raceWith_1$1.raceWith.apply(void 0, __spreadArray([], __read(argsOrArgArray_1.argsOrArgArray(args))));
|
|
10710
10762
|
}
|
|
10711
|
-
exports.race = race$
|
|
10763
|
+
exports.race = race$3;
|
|
10712
10764
|
}));
|
|
10713
10765
|
|
|
10714
10766
|
//#endregion
|
|
@@ -12042,7 +12094,13 @@ var Participant = class extends Destroyable {
|
|
|
12042
12094
|
}
|
|
12043
12095
|
/** Removes this participant from the call. */
|
|
12044
12096
|
async remove() {
|
|
12045
|
-
|
|
12097
|
+
const state = this._state$.value;
|
|
12098
|
+
const target = {
|
|
12099
|
+
member_id: this.id,
|
|
12100
|
+
call_id: state.call_id ?? "",
|
|
12101
|
+
node_id: state.node_id ?? ""
|
|
12102
|
+
};
|
|
12103
|
+
await this.executeMethod(target, "call.member.remove", {});
|
|
12046
12104
|
}
|
|
12047
12105
|
/** Ends the call for this participant. */
|
|
12048
12106
|
async end() {
|
|
@@ -12212,6 +12270,9 @@ function isJSONRPCRequest(value) {
|
|
|
12212
12270
|
function isJSONRPCResponse(value) {
|
|
12213
12271
|
return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && (hasProperty(value, "result") || hasProperty(value, "error"));
|
|
12214
12272
|
}
|
|
12273
|
+
function isJSONRPCErrorResponse(value) {
|
|
12274
|
+
return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && (hasProperty(value, "error") && isObject(value.error) && hasProperty(value.error, "code") && hasProperty(value.error, "message") || hasProperty(value, "result") && isObject(value.result) && hasProperty(value.result, "code") && value.result.code !== "200" && hasProperty(value.result, "message"));
|
|
12275
|
+
}
|
|
12215
12276
|
|
|
12216
12277
|
//#endregion
|
|
12217
12278
|
//#region src/core/RPCMessages/guards/events.guards.ts
|
|
@@ -12401,7 +12462,6 @@ var CallEventsManager = class extends Destroyable {
|
|
|
12401
12462
|
this.options = options;
|
|
12402
12463
|
this.callIds = /* @__PURE__ */ new Set();
|
|
12403
12464
|
this.roomSessionIds = /* @__PURE__ */ new Set();
|
|
12404
|
-
this._status$ = this.createBehaviorSubject("trying");
|
|
12405
12465
|
this._participants$ = this.createBehaviorSubject({});
|
|
12406
12466
|
this._self$ = this.createBehaviorSubject(null);
|
|
12407
12467
|
this._sessionState$ = this.createBehaviorSubject(initialSessionState);
|
|
@@ -12410,15 +12470,12 @@ var CallEventsManager = class extends Destroyable {
|
|
|
12410
12470
|
get participants$() {
|
|
12411
12471
|
return this.cachedObservable("participants$", () => this._participants$.asObservable().pipe((0, import_cjs$14.map)((participantsRecord) => Object.values(participantsRecord))));
|
|
12412
12472
|
}
|
|
12473
|
+
get participants() {
|
|
12474
|
+
return Object.values(this._participants$.value);
|
|
12475
|
+
}
|
|
12413
12476
|
get self$() {
|
|
12414
12477
|
return this.cachedObservable("self$", () => this._self$.asObservable().pipe(filterNull()));
|
|
12415
12478
|
}
|
|
12416
|
-
get status$() {
|
|
12417
|
-
return this._status$.asObservable();
|
|
12418
|
-
}
|
|
12419
|
-
get status() {
|
|
12420
|
-
return this._status$.value;
|
|
12421
|
-
}
|
|
12422
12479
|
isRoomSessionIdValid(roomSessionId) {
|
|
12423
12480
|
return this.roomSessionIds.has(roomSessionId);
|
|
12424
12481
|
}
|
|
@@ -12503,7 +12560,6 @@ var CallEventsManager = class extends Destroyable {
|
|
|
12503
12560
|
callId: callJoinedEvent.call_id,
|
|
12504
12561
|
roomSessionId: callJoinedEvent.room_session_id
|
|
12505
12562
|
});
|
|
12506
|
-
this._status$.next("connected");
|
|
12507
12563
|
const sessionState = callJoinedEvent.room_session;
|
|
12508
12564
|
const { capabilities } = callJoinedEvent;
|
|
12509
12565
|
this.selfId = this.selfId ?? callJoinedEvent.member_id;
|
|
@@ -12630,12 +12686,53 @@ var CallEventsManager = class extends Destroyable {
|
|
|
12630
12686
|
|
|
12631
12687
|
//#endregion
|
|
12632
12688
|
//#region src/helpers/SDPHelper.ts
|
|
12689
|
+
/** Valid SDP direction attribute values. */
|
|
12690
|
+
const SDP_DIRECTIONS = new Set([
|
|
12691
|
+
"sendrecv",
|
|
12692
|
+
"sendonly",
|
|
12693
|
+
"recvonly",
|
|
12694
|
+
"inactive"
|
|
12695
|
+
]);
|
|
12633
12696
|
/**
|
|
12634
|
-
*
|
|
12697
|
+
* Extracts the media directions (audio/video) from an SDP string.
|
|
12698
|
+
*
|
|
12699
|
+
* Parses each media section (`m=audio` / `m=video`) and reads the `a=` direction
|
|
12700
|
+
* attribute (`sendrecv`, `sendonly`, `recvonly`, `inactive`).
|
|
12701
|
+
* If no explicit direction attribute is found for a media section, defaults to `sendrecv`
|
|
12702
|
+
* per RFC 4566.
|
|
12635
12703
|
*
|
|
12636
|
-
*
|
|
12637
|
-
*
|
|
12704
|
+
* @param sdp - The SDP string to parse
|
|
12705
|
+
* @returns The extracted audio and video directions
|
|
12706
|
+
*
|
|
12707
|
+
* @example
|
|
12708
|
+
* ```typescript
|
|
12709
|
+
* const sdp = `v=0\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111\r\na=sendrecv\r\nm=video 9 UDP/TLS/RTP/SAVPF 96\r\na=recvonly`;
|
|
12710
|
+
* extractMediaDirectionsFromSDP(sdp);
|
|
12711
|
+
* // { audio: 'sendrecv', video: 'recvonly' }
|
|
12712
|
+
* ```
|
|
12638
12713
|
*/
|
|
12714
|
+
function extractMediaDirectionsFromSDP(sdp) {
|
|
12715
|
+
const result = {
|
|
12716
|
+
audio: "inactive",
|
|
12717
|
+
video: "inactive"
|
|
12718
|
+
};
|
|
12719
|
+
if (!sdp) return result;
|
|
12720
|
+
const lines = sdp.split(/\r?\n/);
|
|
12721
|
+
let currentMediaKind = null;
|
|
12722
|
+
let currentDirection = null;
|
|
12723
|
+
for (const line of lines) if (line.startsWith("m=")) {
|
|
12724
|
+
if (currentMediaKind) result[currentMediaKind] = currentDirection ?? "sendrecv";
|
|
12725
|
+
if (line.startsWith("m=audio")) currentMediaKind = "audio";
|
|
12726
|
+
else if (line.startsWith("m=video")) currentMediaKind = "video";
|
|
12727
|
+
else currentMediaKind = null;
|
|
12728
|
+
currentDirection = null;
|
|
12729
|
+
} else if (currentMediaKind && line.startsWith("a=")) {
|
|
12730
|
+
const attr = line.substring(2).trim();
|
|
12731
|
+
if (SDP_DIRECTIONS.has(attr)) currentDirection = attr;
|
|
12732
|
+
}
|
|
12733
|
+
if (currentMediaKind) result[currentMediaKind] = currentDirection ?? "sendrecv";
|
|
12734
|
+
return result;
|
|
12735
|
+
}
|
|
12639
12736
|
/**
|
|
12640
12737
|
* Validates that an SDP string has at least one non-host ICE candidate
|
|
12641
12738
|
* for each media section (m= line).
|
|
@@ -12938,6 +13035,15 @@ var LocalStreamController = class extends Destroyable {
|
|
|
12938
13035
|
track.addEventListener("ended", this.mediaTrackEndedHandler);
|
|
12939
13036
|
}
|
|
12940
13037
|
/**
|
|
13038
|
+
* Update the controller options (e.g., when media overrides are applied).
|
|
13039
|
+
*/
|
|
13040
|
+
updateOptions(options) {
|
|
13041
|
+
this.options = {
|
|
13042
|
+
...this.options,
|
|
13043
|
+
...options
|
|
13044
|
+
};
|
|
13045
|
+
}
|
|
13046
|
+
/**
|
|
12941
13047
|
* Stop all local tracks and clean up.
|
|
12942
13048
|
*/
|
|
12943
13049
|
stopAllTracks() {
|
|
@@ -13276,11 +13382,12 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13276
13382
|
this._connectionState$ = this.createReplaySubject(1);
|
|
13277
13383
|
this._signalingState$ = this.createReplaySubject(1);
|
|
13278
13384
|
this._iceGatheringState$ = this.createReplaySubject(1);
|
|
13279
|
-
this._errors$ = this.
|
|
13385
|
+
this._errors$ = this.createReplaySubject(1);
|
|
13280
13386
|
this._iceCandidates$ = this.createReplaySubject(1);
|
|
13281
13387
|
this._initialized$ = this.createReplaySubject(1);
|
|
13282
13388
|
this._remoteDescription$ = this.createReplaySubject(1);
|
|
13283
13389
|
this._remoteStream$ = this.createBehaviorSubject(null);
|
|
13390
|
+
this._remoteOfferMediaDirections = null;
|
|
13284
13391
|
this.deviceController = deviceController ?? {};
|
|
13285
13392
|
this.id = options.callId ?? v4_default();
|
|
13286
13393
|
this._type = remoteSessionDescription ? "answer" : "offer";
|
|
@@ -13288,10 +13395,19 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13288
13395
|
type: "offer",
|
|
13289
13396
|
sdp: remoteSessionDescription
|
|
13290
13397
|
} : void 0;
|
|
13398
|
+
this._remoteOfferMediaDirections = remoteSessionDescription ? extractMediaDirectionsFromSDP(remoteSessionDescription) : null;
|
|
13399
|
+
const offerDefaults = this._remoteOfferMediaDirections ? {
|
|
13400
|
+
audio: this._remoteOfferMediaDirections.audio.includes("recv"),
|
|
13401
|
+
video: this._remoteOfferMediaDirections.video.includes("recv"),
|
|
13402
|
+
receiveAudio: this._remoteOfferMediaDirections.audio.includes("send"),
|
|
13403
|
+
receiveVideo: this._remoteOfferMediaDirections.video.includes("send")
|
|
13404
|
+
} : {};
|
|
13291
13405
|
this.options = {
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
|
|
13406
|
+
...options,
|
|
13407
|
+
audio: options.audio ?? offerDefaults.audio,
|
|
13408
|
+
video: options.video ?? offerDefaults.video,
|
|
13409
|
+
receiveAudio: options.receiveAudio ?? offerDefaults.receiveAudio ?? PreferencesContainer.instance.receiveAudio,
|
|
13410
|
+
receiveVideo: options.receiveVideo ?? offerDefaults.receiveVideo ?? PreferencesContainer.instance.receiveVideo
|
|
13295
13411
|
};
|
|
13296
13412
|
this.localStreamController = new LocalStreamController({
|
|
13297
13413
|
propose: this.propose,
|
|
@@ -13436,7 +13552,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13436
13552
|
};
|
|
13437
13553
|
}
|
|
13438
13554
|
get inputVideoDeviceConstraints() {
|
|
13439
|
-
if (this.options.video
|
|
13555
|
+
if (!this.options.video && !this.options.inputVideoDeviceConstraints) return false;
|
|
13440
13556
|
return {
|
|
13441
13557
|
...this.options.inputVideoDeviceConstraints,
|
|
13442
13558
|
...this.deviceController.selectedVideoInputDeviceConstraints
|
|
@@ -13458,12 +13574,12 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13458
13574
|
default: return {
|
|
13459
13575
|
...options,
|
|
13460
13576
|
offerToReceiveAudio: true,
|
|
13461
|
-
offerToReceiveVideo: Boolean(this.inputVideoDeviceConstraints)
|
|
13577
|
+
offerToReceiveVideo: this.options.receiveVideo ?? Boolean(this.inputVideoDeviceConstraints)
|
|
13462
13578
|
};
|
|
13463
13579
|
}
|
|
13464
13580
|
}
|
|
13465
13581
|
get answerOptions() {
|
|
13466
|
-
return {};
|
|
13582
|
+
return { iceRestart: this.firstSDPExchangeCompleted ? true : void 0 };
|
|
13467
13583
|
}
|
|
13468
13584
|
/**
|
|
13469
13585
|
* Initialize the RTCPeerConnection and setup event listeners.
|
|
@@ -13498,11 +13614,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13498
13614
|
});
|
|
13499
13615
|
await this.updateSelectedInputDevice(kind, deviceInfo);
|
|
13500
13616
|
});
|
|
13501
|
-
await this.setupTrackHandling();
|
|
13502
|
-
this._initialized$.next(true);
|
|
13503
13617
|
if (this.type === "answer" && this.sdpInit) {
|
|
13618
|
+
await this.setupRemoteTracks();
|
|
13619
|
+
this._initialized$.next(true);
|
|
13504
13620
|
this.setupEventListeners();
|
|
13505
|
-
|
|
13621
|
+
this._isNegotiating$.next(true);
|
|
13622
|
+
await this._setRemoteDescription(this.sdpInit);
|
|
13623
|
+
} else {
|
|
13624
|
+
await this.setupTrackHandling();
|
|
13625
|
+
this._initialized$.next(true);
|
|
13506
13626
|
}
|
|
13507
13627
|
} catch (error) {
|
|
13508
13628
|
logger$11.error("[RTCPeerConnectionController] Initialization error:", error);
|
|
@@ -13600,6 +13720,35 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13600
13720
|
default:
|
|
13601
13721
|
}
|
|
13602
13722
|
}
|
|
13723
|
+
/**
|
|
13724
|
+
* Accept an inbound call by creating the SDP answer.
|
|
13725
|
+
* Optionally override media options before the answer is generated.
|
|
13726
|
+
* Must be called after initialization for inbound (answer-type) connections.
|
|
13727
|
+
*/
|
|
13728
|
+
async acceptInbound(mediaOverrides) {
|
|
13729
|
+
if (mediaOverrides) {
|
|
13730
|
+
const { audio, video, receiveAudio, receiveVideo } = mediaOverrides;
|
|
13731
|
+
this.options = {
|
|
13732
|
+
...this.options,
|
|
13733
|
+
...audio !== void 0 ? { audio } : {},
|
|
13734
|
+
...video !== void 0 ? { video } : {},
|
|
13735
|
+
...receiveAudio !== void 0 ? { receiveAudio } : {},
|
|
13736
|
+
...receiveVideo !== void 0 ? { receiveVideo } : {}
|
|
13737
|
+
};
|
|
13738
|
+
this.transceiverController?.updateOptions({
|
|
13739
|
+
receiveAudio: this.receiveAudio,
|
|
13740
|
+
receiveVideo: this.receiveVideo
|
|
13741
|
+
});
|
|
13742
|
+
this.localStreamController.updateOptions({
|
|
13743
|
+
inputAudioDeviceConstraints: this.inputAudioDeviceConstraints,
|
|
13744
|
+
inputVideoDeviceConstraints: this.inputVideoDeviceConstraints
|
|
13745
|
+
});
|
|
13746
|
+
}
|
|
13747
|
+
await this.setupLocalTracks();
|
|
13748
|
+
const { answerOptions } = this;
|
|
13749
|
+
logger$11.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
|
|
13750
|
+
await this.createAnswer(answerOptions);
|
|
13751
|
+
}
|
|
13603
13752
|
async handleOfferReceived() {
|
|
13604
13753
|
if (!this.sdpInit) throw new DependencyError("SDP initialization parameters are not set");
|
|
13605
13754
|
this._isNegotiating$.next(true);
|
|
@@ -13674,37 +13823,29 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13674
13823
|
}
|
|
13675
13824
|
async setupLocalTracks() {
|
|
13676
13825
|
logger$11.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
|
|
13677
|
-
|
|
13678
|
-
if (
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
if (localStream) {
|
|
13685
|
-
if (this.transceiverController?.useAddStream ?? false) {
|
|
13686
|
-
logger$11.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
|
|
13687
|
-
this.peerConnection?.addStream(localStream);
|
|
13688
|
-
if (!this.isNegotiating) {
|
|
13689
|
-
logger$11.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
|
|
13690
|
-
this.negotiationNeeded$.next();
|
|
13691
|
-
}
|
|
13692
|
-
return;
|
|
13826
|
+
const localStream = this.localStream ?? await this.localStreamController.buildLocalStream();
|
|
13827
|
+
if (this.transceiverController?.useAddStream ?? false) {
|
|
13828
|
+
logger$11.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
|
|
13829
|
+
this.peerConnection?.addStream(localStream);
|
|
13830
|
+
if (!this.isNegotiating) {
|
|
13831
|
+
logger$11.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
|
|
13832
|
+
this.negotiationNeeded$.next();
|
|
13693
13833
|
}
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
}
|
|
13834
|
+
return;
|
|
13835
|
+
}
|
|
13836
|
+
for (const kind of ["audio", "video"]) {
|
|
13837
|
+
const tracks = (kind === "audio" ? localStream.getAudioTracks() : localStream.getVideoTracks()).map((track, index) => ({
|
|
13838
|
+
index,
|
|
13839
|
+
track
|
|
13840
|
+
}));
|
|
13841
|
+
for (const { index, track } of tracks) {
|
|
13842
|
+
this.localStreamController.addTrackEndedListener(track);
|
|
13843
|
+
if (this.transceiverController?.useAddTransceivers ?? false) {
|
|
13844
|
+
const transceivers = (kind === "audio" ? this.transceiverController?.audioTransceivers : this.transceiverController?.videoTransceivers) ?? [];
|
|
13845
|
+
await this.transceiverController?.setupTransceiverSender(track, localStream, transceivers[index]);
|
|
13846
|
+
} else {
|
|
13847
|
+
logger$11.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
|
|
13848
|
+
this.peerConnection?.addTrack(track, localStream);
|
|
13708
13849
|
}
|
|
13709
13850
|
}
|
|
13710
13851
|
}
|
|
@@ -13721,7 +13862,12 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13721
13862
|
if (!this.peerConnection) throw new DependencyError("RTCPeerConnection is not initialized");
|
|
13722
13863
|
this.peerConnection.ontrack = (event) => {
|
|
13723
13864
|
logger$11.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
|
|
13724
|
-
this._remoteStream$.next(event.streams[0]);
|
|
13865
|
+
if (event.streams[0]) this._remoteStream$.next(event.streams[0]);
|
|
13866
|
+
else {
|
|
13867
|
+
const existingTracks = this._remoteStream$.value?.getTracks() ?? [];
|
|
13868
|
+
const newStream = new MediaStream([...existingTracks, event.track]);
|
|
13869
|
+
this._remoteStream$.next(newStream);
|
|
13870
|
+
}
|
|
13725
13871
|
};
|
|
13726
13872
|
await this.transceiverController?.setupRemoteTransceivers(this.type);
|
|
13727
13873
|
}
|
|
@@ -13820,7 +13966,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
13820
13966
|
});
|
|
13821
13967
|
}
|
|
13822
13968
|
get mediaDirections() {
|
|
13823
|
-
return this.transceiverController?.getMediaDirections() ?? {
|
|
13969
|
+
return this.transceiverController?.getMediaDirections() ?? this._remoteOfferMediaDirections ?? {
|
|
13824
13970
|
audio: "inactive",
|
|
13825
13971
|
video: "inactive"
|
|
13826
13972
|
};
|
|
@@ -13969,6 +14115,11 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
13969
14115
|
].includes(connectionState)))));
|
|
13970
14116
|
}
|
|
13971
14117
|
initSubscriptions() {
|
|
14118
|
+
this.subscribeTo(this.callJoinedEvent$, (event) => {
|
|
14119
|
+
const memberNodeId = event.room_session.members.find((m) => m.call_id === event.call_id)?.node_id;
|
|
14120
|
+
if (memberNodeId) this.setNodeIdIfNull(memberNodeId);
|
|
14121
|
+
if (event.member_id) this.setSelfIdIfNull(event.member_id);
|
|
14122
|
+
});
|
|
13972
14123
|
this.subscribeTo(this.vertoMedia$, (event) => {
|
|
13973
14124
|
logger$10.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
|
|
13974
14125
|
this._signalingStatus$.next("ringing");
|
|
@@ -13980,6 +14131,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
13980
14131
|
});
|
|
13981
14132
|
this.subscribeTo(this.vertoAnswer$, (event) => {
|
|
13982
14133
|
logger$10.debug("[WebRTCManager] Received Verto answer event:", event);
|
|
14134
|
+
this._signalingStatus$.next("connecting");
|
|
13983
14135
|
const { sdp, callID } = event;
|
|
13984
14136
|
this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
|
|
13985
14137
|
status: "received",
|
|
@@ -13999,6 +14151,28 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
13999
14151
|
this.sendVertoPong(vertoPing);
|
|
14000
14152
|
});
|
|
14001
14153
|
}
|
|
14154
|
+
/**
|
|
14155
|
+
* Set node_id/selfId only when the current value is null.
|
|
14156
|
+
*
|
|
14157
|
+
* During reattach, `call.joined` and `verto.answer` events can deliver
|
|
14158
|
+
* these identifiers before the `verto.invite` RPC response (`CALL CREATED`)
|
|
14159
|
+
* arrives. These methods let early events populate them eagerly so that
|
|
14160
|
+
* downstream RPC calls (e.g. `call.layout.list`) don't fail with empty
|
|
14161
|
+
* identifiers. `processInviteResponse()` remains the authoritative source
|
|
14162
|
+
* and always overwrites unconditionally.
|
|
14163
|
+
*/
|
|
14164
|
+
setNodeIdIfNull(nodeId) {
|
|
14165
|
+
if (!this._nodeId$.value && nodeId) {
|
|
14166
|
+
logger$10.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
|
|
14167
|
+
this._nodeId$.next(nodeId);
|
|
14168
|
+
}
|
|
14169
|
+
}
|
|
14170
|
+
setSelfIdIfNull(selfId) {
|
|
14171
|
+
if (!this._selfId$.value && selfId) {
|
|
14172
|
+
logger$10.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
|
|
14173
|
+
this._selfId$.next(selfId);
|
|
14174
|
+
}
|
|
14175
|
+
}
|
|
14002
14176
|
async sendVertoPong(vertoPing) {
|
|
14003
14177
|
try {
|
|
14004
14178
|
const vertoPongMessage = VertoPong({ ...vertoPing });
|
|
@@ -14022,6 +14196,9 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
14022
14196
|
get selfId() {
|
|
14023
14197
|
return this._selfId$.value;
|
|
14024
14198
|
}
|
|
14199
|
+
get callJoinedEvent$() {
|
|
14200
|
+
return this.webRtcCallSession.callEvent$.pipe((0, import_cjs$10.filter)(isCallJoinedPayload), (0, import_cjs$10.takeUntil)(this.destroyed$));
|
|
14201
|
+
}
|
|
14025
14202
|
get vertoMedia$() {
|
|
14026
14203
|
return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$));
|
|
14027
14204
|
}
|
|
@@ -14051,13 +14228,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
14051
14228
|
if (response.error) {
|
|
14052
14229
|
const error = new JSONRPCError(response.error.code, response.error.message, response.error.data);
|
|
14053
14230
|
this.onError?.(error);
|
|
14054
|
-
|
|
14231
|
+
return response;
|
|
14055
14232
|
}
|
|
14056
14233
|
const innerResult = getValueFrom(response, "result.result");
|
|
14057
14234
|
if (innerResult?.error) {
|
|
14058
14235
|
const error = new JSONRPCError(innerResult.error.code, innerResult.error.message, innerResult.error.data);
|
|
14059
14236
|
this.onError?.(error);
|
|
14060
|
-
|
|
14237
|
+
return response;
|
|
14061
14238
|
}
|
|
14062
14239
|
return response;
|
|
14063
14240
|
}
|
|
@@ -14077,7 +14254,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
14077
14254
|
}
|
|
14078
14255
|
} catch (error) {
|
|
14079
14256
|
logger$10.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
|
|
14080
|
-
|
|
14257
|
+
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
14081
14258
|
}
|
|
14082
14259
|
}
|
|
14083
14260
|
async processModifyResponse(response, rtcPeerConnController) {
|
|
@@ -14091,12 +14268,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
14091
14268
|
});
|
|
14092
14269
|
} catch (error) {
|
|
14093
14270
|
logger$10.warn("[WebRTCManager] Error processing modify response:", error);
|
|
14094
|
-
|
|
14271
|
+
const modifyError = error instanceof Error ? error : new Error(String(error), { cause: error });
|
|
14272
|
+
this.onError?.(modifyError);
|
|
14095
14273
|
}
|
|
14096
14274
|
}
|
|
14097
14275
|
}
|
|
14098
14276
|
processInviteResponse(response, rtcPeerConnController) {
|
|
14099
14277
|
if (!response.error && getValueFrom(response, "result.result.result.message") === "CALL CREATED") {
|
|
14278
|
+
this._signalingStatus$.next("trying");
|
|
14100
14279
|
this._nodeId$.next(getValueFrom(response, "result.node_id") ?? null);
|
|
14101
14280
|
const memberId = getValueFrom(response, "result.result.result.memberID") ?? null;
|
|
14102
14281
|
const callId = getValueFrom(response, "result.result.result.callID") ?? null;
|
|
@@ -14151,6 +14330,36 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
14151
14330
|
this.subscribeTo(rtcPeerConnController.errors$, (error) => {
|
|
14152
14331
|
this.onError?.(error);
|
|
14153
14332
|
});
|
|
14333
|
+
if (options.initOffer) this.handleInboundAnswer(rtcPeerConnController);
|
|
14334
|
+
}
|
|
14335
|
+
async handleInboundAnswer(rtcPeerConnController) {
|
|
14336
|
+
logger$10.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
|
|
14337
|
+
const vertoByeOrAccepted = await (0, import_cjs$10.firstValueFrom)((0, import_cjs$10.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, import_cjs$10.takeUntil)(this.destroyed$))).catch(() => null);
|
|
14338
|
+
if (vertoByeOrAccepted === null) {
|
|
14339
|
+
logger$10.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
|
|
14340
|
+
return;
|
|
14341
|
+
}
|
|
14342
|
+
if (isVertoByeMessage(vertoByeOrAccepted)) {
|
|
14343
|
+
logger$10.info("[WebRTCManager] Inbound call ended by remote before answer.");
|
|
14344
|
+
this.callSession?.destroy();
|
|
14345
|
+
} else if (!vertoByeOrAccepted) {
|
|
14346
|
+
logger$10.info("[WebRTCManager] Inbound call rejected by user.");
|
|
14347
|
+
try {
|
|
14348
|
+
await this.bye("USER_BUSY");
|
|
14349
|
+
} finally {
|
|
14350
|
+
this._signalingStatus$.next("disconnected");
|
|
14351
|
+
this.callSession?.destroy();
|
|
14352
|
+
}
|
|
14353
|
+
} else {
|
|
14354
|
+
logger$10.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
|
|
14355
|
+
const answerOptions = this.webRtcCallSession.answerMediaOptions;
|
|
14356
|
+
try {
|
|
14357
|
+
await rtcPeerConnController.acceptInbound(answerOptions);
|
|
14358
|
+
} catch (error) {
|
|
14359
|
+
logger$10.error("[WebRTCManager] Error creating inbound answer:", error);
|
|
14360
|
+
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
14361
|
+
}
|
|
14362
|
+
}
|
|
14154
14363
|
}
|
|
14155
14364
|
setupVertoAttachHandler() {
|
|
14156
14365
|
this.subscribeTo(this.vertoAttach$, async (vertoAttach) => {
|
|
@@ -14168,7 +14377,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
14168
14377
|
});
|
|
14169
14378
|
}
|
|
14170
14379
|
initObservables(rtcPeerConnController) {
|
|
14171
|
-
this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, import_cjs$10.filter)((state) => state === "connected"), (0, import_cjs$10.
|
|
14380
|
+
this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, import_cjs$10.filter)((state) => state === "connected"), (0, import_cjs$10.map)(() => rtcPeerConnController.mediaDirections), (0, import_cjs$10.startWith)(rtcPeerConnController.mediaDirections), (0, import_cjs$10.takeUntil)(this.destroyed$));
|
|
14172
14381
|
this.localStream$ = rtcPeerConnController.localStream$.pipe(filterNull(), (0, import_cjs$10.takeUntil)(this.destroyed$));
|
|
14173
14382
|
this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(filterNull(), (0, import_cjs$10.takeUntil)(this.destroyed$));
|
|
14174
14383
|
}
|
|
@@ -14184,7 +14393,6 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
14184
14393
|
});
|
|
14185
14394
|
this.sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnController);
|
|
14186
14395
|
} else if (initial) {
|
|
14187
|
-
this._signalingStatus$.next("trying");
|
|
14188
14396
|
const vertoMessageRequest = VertoInvite({
|
|
14189
14397
|
dialogParams,
|
|
14190
14398
|
sdp
|
|
@@ -14491,8 +14699,8 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14491
14699
|
this.clientSession = clientSession;
|
|
14492
14700
|
this.options = options;
|
|
14493
14701
|
this.address = address;
|
|
14494
|
-
this.
|
|
14495
|
-
this.
|
|
14702
|
+
this._errors$ = this.createReplaySubject(1);
|
|
14703
|
+
this._lastMergedStatus = "new";
|
|
14496
14704
|
this._answered$ = this.createReplaySubject();
|
|
14497
14705
|
this._holdState = false;
|
|
14498
14706
|
this._userVariables$ = this.createBehaviorSubject({ ...PreferencesContainer.instance.userVariables });
|
|
@@ -14513,18 +14721,28 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14513
14721
|
const managers = initialization.initializeManagers(this);
|
|
14514
14722
|
this.vertoManager = managers.vertoManager;
|
|
14515
14723
|
this.callEventsManager = managers.callEventsManager;
|
|
14516
|
-
if (options.initOffer)
|
|
14517
|
-
|
|
14724
|
+
if (options.initOffer) {
|
|
14725
|
+
this._status$ = this.createBehaviorSubject("ringing");
|
|
14726
|
+
this._lastMergedStatus = "ringing";
|
|
14727
|
+
} else this._status$ = this.createBehaviorSubject("new");
|
|
14518
14728
|
const { deviceController } = initialization;
|
|
14519
14729
|
this.participantFactory = new ParticipantFactory(this.executeMethod.bind(this), this.vertoManager, deviceController);
|
|
14520
14730
|
}
|
|
14521
14731
|
/** Observable stream of errors from media, signaling, and peer connection layers. */
|
|
14522
14732
|
get errors$() {
|
|
14523
|
-
return this._errors$.asObservable();
|
|
14733
|
+
return this.deferEmission(this._errors$.asObservable());
|
|
14524
14734
|
}
|
|
14525
|
-
/**
|
|
14526
|
-
|
|
14527
|
-
|
|
14735
|
+
/**
|
|
14736
|
+
* @internal Push an error to the call's error stream.
|
|
14737
|
+
* Fatal errors automatically transition the call to `'failed'` and destroy it.
|
|
14738
|
+
*/
|
|
14739
|
+
emitError(callError) {
|
|
14740
|
+
if (this._status$.value === "destroyed" || this._status$.value === "failed") return;
|
|
14741
|
+
this._errors$.next(callError);
|
|
14742
|
+
if (callError.fatal) {
|
|
14743
|
+
this._status$.next("failed");
|
|
14744
|
+
this.destroy();
|
|
14745
|
+
}
|
|
14528
14746
|
}
|
|
14529
14747
|
/** Whether this call is `'inbound'` or `'outbound'`. */
|
|
14530
14748
|
get direction() {
|
|
@@ -14532,7 +14750,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14532
14750
|
}
|
|
14533
14751
|
/** Observable of the address associated with this call. */
|
|
14534
14752
|
get address$() {
|
|
14535
|
-
return (0, import_cjs$9.from)([this.address]);
|
|
14753
|
+
return this.deferEmission((0, import_cjs$9.from)([this.address])).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14536
14754
|
}
|
|
14537
14755
|
/** Display name of the caller. */
|
|
14538
14756
|
get fromName() {
|
|
@@ -14564,7 +14782,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14564
14782
|
}
|
|
14565
14783
|
/** Current snapshot of all participants in the call. */
|
|
14566
14784
|
get participants() {
|
|
14567
|
-
return
|
|
14785
|
+
return this.callEventsManager.participants;
|
|
14568
14786
|
}
|
|
14569
14787
|
/** The local participant, or `null` if not yet joined. */
|
|
14570
14788
|
get self() {
|
|
@@ -14573,7 +14791,6 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14573
14791
|
async toggleLock() {
|
|
14574
14792
|
const method = this.locked ? "call.unlock" : "call.lock";
|
|
14575
14793
|
await this.executeMethod(this.selfId ?? "", method, {});
|
|
14576
|
-
throw new UnimplementedError();
|
|
14577
14794
|
}
|
|
14578
14795
|
async toggleHold() {
|
|
14579
14796
|
if (this._holdState) await this.vertoManager.unhold();
|
|
@@ -14594,7 +14811,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14594
14811
|
}
|
|
14595
14812
|
/** Observable of layout layer positions for all participants. */
|
|
14596
14813
|
get layoutLayers$() {
|
|
14597
|
-
return this.callEventsManager.layoutLayers
|
|
14814
|
+
return this.deferEmission(this.callEventsManager.layoutLayers$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14598
14815
|
}
|
|
14599
14816
|
/** Current snapshot of layout layers. */
|
|
14600
14817
|
get layoutLayers() {
|
|
@@ -14608,72 +14825,80 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14608
14825
|
params
|
|
14609
14826
|
});
|
|
14610
14827
|
try {
|
|
14611
|
-
|
|
14828
|
+
const response = await this.clientSession.execute(request);
|
|
14829
|
+
if (isJSONRPCErrorResponse(response)) throw new JSONRPCError(parseInt(response.result?.code ?? "0"), `Error response from method ${method}: ${response.result?.code} ${response.result?.message}`, void 0, void 0, request.id);
|
|
14830
|
+
return response;
|
|
14612
14831
|
} catch (error) {
|
|
14613
14832
|
logger$9.error(`[Call] Error executing method ${method} with params`, params, error);
|
|
14614
14833
|
throw error;
|
|
14615
14834
|
}
|
|
14616
14835
|
}
|
|
14617
14836
|
buildMethodParams(target, args) {
|
|
14618
|
-
const
|
|
14619
|
-
node_id: this.nodeId,
|
|
14620
|
-
call_id: this.id
|
|
14837
|
+
const self = {
|
|
14838
|
+
node_id: this.nodeId ?? "",
|
|
14839
|
+
call_id: this.id,
|
|
14840
|
+
member_id: this.vertoManager.selfId ?? ""
|
|
14841
|
+
};
|
|
14842
|
+
if (typeof target === "object") return {
|
|
14843
|
+
...args,
|
|
14844
|
+
self,
|
|
14845
|
+
targets: [target]
|
|
14621
14846
|
};
|
|
14622
14847
|
return {
|
|
14623
14848
|
...args,
|
|
14624
|
-
self
|
|
14625
|
-
...reference,
|
|
14626
|
-
member_id: this.vertoManager.selfId
|
|
14627
|
-
},
|
|
14849
|
+
self,
|
|
14628
14850
|
target: {
|
|
14629
|
-
|
|
14851
|
+
node_id: this.nodeId ?? "",
|
|
14852
|
+
call_id: this.id,
|
|
14630
14853
|
member_id: target
|
|
14631
14854
|
}
|
|
14632
14855
|
};
|
|
14633
14856
|
}
|
|
14634
14857
|
/** Observable of the current call status (e.g. `'ringing'`, `'connected'`). */
|
|
14635
14858
|
get status$() {
|
|
14636
|
-
return this.
|
|
14859
|
+
return this.publicCachedObservable("status$", () => (0, import_cjs$9.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$).pipe((0, import_cjs$9.distinctUntilChanged)(), (0, import_cjs$9.tap)((status) => {
|
|
14860
|
+
this._lastMergedStatus = status;
|
|
14861
|
+
})));
|
|
14637
14862
|
}
|
|
14638
14863
|
/** Observable of the participants list, emits on join/leave/update. */
|
|
14639
14864
|
get participants$() {
|
|
14640
|
-
return this.callEventsManager.participants
|
|
14865
|
+
return this.deferEmission(this.callEventsManager.participants$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14641
14866
|
}
|
|
14642
14867
|
/** Observable of the local (self) participant. */
|
|
14643
14868
|
get self$() {
|
|
14644
|
-
return this.callEventsManager.self
|
|
14869
|
+
return this.deferEmission(this.callEventsManager.self$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14645
14870
|
}
|
|
14646
14871
|
/** Observable indicating whether the call is being recorded. */
|
|
14647
14872
|
get recording$() {
|
|
14648
|
-
return this.callEventsManager.recording
|
|
14873
|
+
return this.deferEmission(this.callEventsManager.recording$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14649
14874
|
}
|
|
14650
14875
|
/** Observable indicating whether the call is being streamed. */
|
|
14651
14876
|
get streaming$() {
|
|
14652
|
-
return this.callEventsManager.streaming
|
|
14877
|
+
return this.deferEmission(this.callEventsManager.streaming$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14653
14878
|
}
|
|
14654
14879
|
/** Observable indicating whether raise-hand priority is active. */
|
|
14655
14880
|
get raiseHandPriority$() {
|
|
14656
|
-
return this.callEventsManager.raiseHandPriority
|
|
14881
|
+
return this.deferEmission(this.callEventsManager.raiseHandPriority$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14657
14882
|
}
|
|
14658
14883
|
/** Observable indicating whether the call room is locked. */
|
|
14659
14884
|
get locked$() {
|
|
14660
|
-
return this.callEventsManager.locked
|
|
14885
|
+
return this.deferEmission(this.callEventsManager.locked$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14661
14886
|
}
|
|
14662
14887
|
/** Observable of custom metadata associated with the call. */
|
|
14663
14888
|
get meta$() {
|
|
14664
|
-
return this.callEventsManager.meta
|
|
14889
|
+
return this.deferEmission(this.callEventsManager.meta$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14665
14890
|
}
|
|
14666
14891
|
/** Observable of the call's capability flags. */
|
|
14667
14892
|
get capabilities$() {
|
|
14668
|
-
return this.callEventsManager.capabilities
|
|
14893
|
+
return this.deferEmission(this.callEventsManager.capabilities$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14669
14894
|
}
|
|
14670
14895
|
/** Observable of the current layout name. */
|
|
14671
14896
|
get layout$() {
|
|
14672
|
-
return this.callEventsManager.layout
|
|
14897
|
+
return this.deferEmission(this.callEventsManager.layout$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14673
14898
|
}
|
|
14674
14899
|
/** Current call status. */
|
|
14675
14900
|
get status() {
|
|
14676
|
-
return this.
|
|
14901
|
+
return this._lastMergedStatus;
|
|
14677
14902
|
}
|
|
14678
14903
|
/** Whether the call is currently being recorded. */
|
|
14679
14904
|
get recording() {
|
|
@@ -14701,7 +14926,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14701
14926
|
}
|
|
14702
14927
|
/** Observable of available layout names. */
|
|
14703
14928
|
get layouts$() {
|
|
14704
|
-
return this.callEventsManager.layouts
|
|
14929
|
+
return this.deferEmission(this.callEventsManager.layouts$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14705
14930
|
}
|
|
14706
14931
|
/** Current snapshot of available layout names. */
|
|
14707
14932
|
get layouts() {
|
|
@@ -14709,7 +14934,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14709
14934
|
}
|
|
14710
14935
|
/** Observable of the local media stream (camera/microphone). */
|
|
14711
14936
|
get localStream$() {
|
|
14712
|
-
return this.vertoManager.localStream
|
|
14937
|
+
return this.deferEmission(this.vertoManager.localStream$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14713
14938
|
}
|
|
14714
14939
|
/** Current local media stream, or `null` if not available. */
|
|
14715
14940
|
get localStream() {
|
|
@@ -14717,7 +14942,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14717
14942
|
}
|
|
14718
14943
|
/** Observable of the remote media stream from the far end. */
|
|
14719
14944
|
get remoteStream$() {
|
|
14720
|
-
return this.vertoManager.remoteStream
|
|
14945
|
+
return this.deferEmission(this.vertoManager.remoteStream$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14721
14946
|
}
|
|
14722
14947
|
/** Current remote media stream, or `null` if not available. */
|
|
14723
14948
|
get remoteStream() {
|
|
@@ -14725,7 +14950,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14725
14950
|
}
|
|
14726
14951
|
/** Observable of custom user variables associated with the call. */
|
|
14727
14952
|
get userVariables$() {
|
|
14728
|
-
return this._userVariables$.asObservable();
|
|
14953
|
+
return this.deferEmission(this._userVariables$.asObservable());
|
|
14729
14954
|
}
|
|
14730
14955
|
/** a copy of the current custom user variables of the call. */
|
|
14731
14956
|
get userVariables() {
|
|
@@ -14745,7 +14970,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14745
14970
|
}
|
|
14746
14971
|
/** Observable of the current audio/video send/receive directions. */
|
|
14747
14972
|
get mediaDirections$() {
|
|
14748
|
-
return this.vertoManager.mediaDirections
|
|
14973
|
+
return this.deferEmission(this.vertoManager.mediaDirections$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
|
|
14749
14974
|
}
|
|
14750
14975
|
/** Current audio/video send/receive directions. */
|
|
14751
14976
|
get mediaDirections() {
|
|
@@ -14791,31 +15016,31 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14791
15016
|
}
|
|
14792
15017
|
/** Observable of call-updated events. */
|
|
14793
15018
|
get callUpdated$() {
|
|
14794
|
-
return this.
|
|
15019
|
+
return this.publicCachedObservable("callUpdated$", () => this.callSessionEvents$.pipe(filterAs(isCallUpdatedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
|
|
14795
15020
|
}
|
|
14796
15021
|
/** Observable of member-joined events. */
|
|
14797
15022
|
get memberJoined$() {
|
|
14798
|
-
return this.
|
|
15023
|
+
return this.publicCachedObservable("memberJoined$", () => this.callSessionEvents$.pipe(filterAs(isMemberJoinedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
|
|
14799
15024
|
}
|
|
14800
15025
|
/** Observable of member-left events. */
|
|
14801
15026
|
get memberLeft$() {
|
|
14802
|
-
return this.
|
|
15027
|
+
return this.publicCachedObservable("memberLeft$", () => this.callSessionEvents$.pipe(filterAs(isMemberLeftMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
|
|
14803
15028
|
}
|
|
14804
15029
|
/** Observable of member-updated events (mute, volume, etc.). */
|
|
14805
15030
|
get memberUpdated$() {
|
|
14806
|
-
return this.
|
|
15031
|
+
return this.publicCachedObservable("memberUpdated$", () => this.callSessionEvents$.pipe(filterAs(isMemberUpdatedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
|
|
14807
15032
|
}
|
|
14808
15033
|
/** Observable of member-talking events (speech start/stop). */
|
|
14809
15034
|
get memberTalking$() {
|
|
14810
|
-
return this.
|
|
15035
|
+
return this.publicCachedObservable("memberTalking$", () => this.callSessionEvents$.pipe(filterAs(isMemberTalkingMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
|
|
14811
15036
|
}
|
|
14812
15037
|
/** Observable of call state-change events. */
|
|
14813
15038
|
get callStates$() {
|
|
14814
|
-
return this.
|
|
15039
|
+
return this.publicCachedObservable("callStates$", () => this.callSessionEvents$.pipe(filterAs(isCallStateMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
|
|
14815
15040
|
}
|
|
14816
15041
|
/** Observable of layout-changed events. */
|
|
14817
15042
|
get layoutUpdates$() {
|
|
14818
|
-
return this.
|
|
15043
|
+
return this.publicCachedObservable("layoutUpdates$", () => this.callSessionEvents$.pipe(filterAs(isLayoutChangedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
|
|
14819
15044
|
}
|
|
14820
15045
|
/** Underlying `RTCPeerConnection`, for advanced use cases. */
|
|
14821
15046
|
get rtcPeerConnection() {
|
|
@@ -14823,7 +15048,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14823
15048
|
}
|
|
14824
15049
|
/** Observable of raw signaling events as plain objects. */
|
|
14825
15050
|
get signalingEvent$() {
|
|
14826
|
-
return this.
|
|
15051
|
+
return this.publicCachedObservable("signalingEvent$", () => this.callEvent$.pipe((0, import_cjs$9.map)((event) => JSON.parse(JSON.stringify(event)))));
|
|
14827
15052
|
}
|
|
14828
15053
|
/** Observable of WebRTC-specific signaling messages. */
|
|
14829
15054
|
get webrtcMessages$() {
|
|
@@ -14850,17 +15075,22 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14850
15075
|
async sendDigits(dtmf) {
|
|
14851
15076
|
return this.vertoManager.sendDigits(dtmf);
|
|
14852
15077
|
}
|
|
14853
|
-
/** Accepts an inbound call. */
|
|
14854
|
-
answer() {
|
|
15078
|
+
/** Accepts an inbound call, optionally overriding media options for the answer. */
|
|
15079
|
+
answer(options) {
|
|
15080
|
+
this._answerMediaOptions = options;
|
|
14855
15081
|
this._answered$.next(true);
|
|
14856
15082
|
}
|
|
15083
|
+
/** Media options provided when answering. Used internally by the VertoManager. */
|
|
15084
|
+
get answerMediaOptions() {
|
|
15085
|
+
return this._answerMediaOptions;
|
|
15086
|
+
}
|
|
14857
15087
|
/** Rejects an inbound call. */
|
|
14858
15088
|
reject() {
|
|
14859
15089
|
this._answered$.next(false);
|
|
14860
15090
|
}
|
|
14861
15091
|
/** Observable that emits `true` when answered, `false` when rejected. */
|
|
14862
15092
|
get answered$() {
|
|
14863
|
-
return this._answered$.asObservable();
|
|
15093
|
+
return this.deferEmission(this._answered$.asObservable());
|
|
14864
15094
|
}
|
|
14865
15095
|
/**
|
|
14866
15096
|
* Sets the call layout and participant positions.
|
|
@@ -14881,10 +15111,10 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14881
15111
|
}
|
|
14882
15112
|
/** Destroys the call, releasing all resources and subscriptions. */
|
|
14883
15113
|
destroy() {
|
|
15114
|
+
if (this._status$.value === "destroyed") return;
|
|
14884
15115
|
this._status$.next("destroyed");
|
|
14885
15116
|
this.vertoManager.destroy();
|
|
14886
15117
|
this.callEventsManager.destroy();
|
|
14887
|
-
this.participantsMap.clear();
|
|
14888
15118
|
super.destroy();
|
|
14889
15119
|
}
|
|
14890
15120
|
};
|
|
@@ -14892,6 +15122,23 @@ var WebRTCCall = class extends Destroyable {
|
|
|
14892
15122
|
//#endregion
|
|
14893
15123
|
//#region src/managers/CallFactory.ts
|
|
14894
15124
|
/**
|
|
15125
|
+
* Infers the semantic error category from a raw Error thrown by VertoManager
|
|
15126
|
+
* or an RTCPeerConnection layer.
|
|
15127
|
+
*/
|
|
15128
|
+
function inferCallErrorKind(error) {
|
|
15129
|
+
if (error instanceof RPCTimeoutError) return "timeout";
|
|
15130
|
+
if (error instanceof JSONRPCError) return "signaling";
|
|
15131
|
+
if (error instanceof MediaTrackError) return "media";
|
|
15132
|
+
if (error instanceof WebSocketConnectionError || error instanceof TransportConnectionError) return "network";
|
|
15133
|
+
return "internal";
|
|
15134
|
+
}
|
|
15135
|
+
/** Determines whether an error should be fatal (destroy the call). */
|
|
15136
|
+
function isFatalError(error) {
|
|
15137
|
+
if (error instanceof VertoPongError) return false;
|
|
15138
|
+
if (error instanceof MediaTrackError) return false;
|
|
15139
|
+
return true;
|
|
15140
|
+
}
|
|
15141
|
+
/**
|
|
14895
15142
|
* Factory for creating WebRTCCall instances with proper manager wiring.
|
|
14896
15143
|
* Eliminates circular dependencies by centralizing Call and Manager creation.
|
|
14897
15144
|
*/
|
|
@@ -14912,7 +15159,13 @@ var CallFactory = class {
|
|
|
14912
15159
|
vertoManager: new WebRTCVertoManager(callInstance, this.attachManager, this.deviceController, this.webRTCApiProvider, {
|
|
14913
15160
|
nodeId: options.nodeId,
|
|
14914
15161
|
onError: (error) => {
|
|
14915
|
-
|
|
15162
|
+
const callError = {
|
|
15163
|
+
kind: inferCallErrorKind(error),
|
|
15164
|
+
fatal: isFatalError(error),
|
|
15165
|
+
error,
|
|
15166
|
+
callId: callInstance.id
|
|
15167
|
+
};
|
|
15168
|
+
callInstance.emitError(callError);
|
|
14916
15169
|
}
|
|
14917
15170
|
}),
|
|
14918
15171
|
callEventsManager: new CallEventsManager(callInstance)
|
|
@@ -15292,9 +15545,15 @@ var PendingRPC = class PendingRPC {
|
|
|
15292
15545
|
return () => signal.removeEventListener("abort", abortHandler);
|
|
15293
15546
|
}) : import_cjs$6.NEVER).subscribe({
|
|
15294
15547
|
next: (response) => {
|
|
15295
|
-
logger$7.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
|
|
15296
15548
|
isSettled = true;
|
|
15297
|
-
|
|
15549
|
+
if (response.error) {
|
|
15550
|
+
const rpcError = new JSONRPCError(response.error.code, response.error.message, response.error.data, void 0, request.id);
|
|
15551
|
+
logger$7.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with RPC error:`, rpcError);
|
|
15552
|
+
reject(rpcError);
|
|
15553
|
+
} else {
|
|
15554
|
+
logger$7.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
|
|
15555
|
+
resolve(response);
|
|
15556
|
+
}
|
|
15298
15557
|
subscription.unsubscribe();
|
|
15299
15558
|
},
|
|
15300
15559
|
error: (error) => {
|
|
@@ -15351,7 +15610,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
15351
15610
|
revision: 0
|
|
15352
15611
|
};
|
|
15353
15612
|
this._authorization$ = this.createBehaviorSubject(void 0);
|
|
15354
|
-
this._errors$ = this.
|
|
15613
|
+
this._errors$ = this.createReplaySubject(1);
|
|
15355
15614
|
this._authenticated$ = this.createBehaviorSubject(false);
|
|
15356
15615
|
this._subscriberInfo$ = this.createBehaviorSubject(null);
|
|
15357
15616
|
this._calls$ = this.createBehaviorSubject({});
|
|
@@ -15579,6 +15838,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
15579
15838
|
...params,
|
|
15580
15839
|
...persistedParams
|
|
15581
15840
|
});
|
|
15841
|
+
this.transport.resetSessionEpoch();
|
|
15582
15842
|
const response = await (0, import_cjs$5.lastValueFrom)((0, import_cjs$5.from)(this.transport.execute(rpcConnectRequest)).pipe(throwOnRPCError(), (0, import_cjs$5.map)((res) => res.result), (0, import_cjs$5.filter)(isRPCConnectResult), (0, import_cjs$5.tap)(() => {
|
|
15583
15843
|
logger$6.debug("[Session] Response passed filter, processing authentication result");
|
|
15584
15844
|
}), (0, import_cjs$5.take)(1), (0, import_cjs$5.catchError)((err) => {
|
|
@@ -15621,12 +15881,13 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
15621
15881
|
}
|
|
15622
15882
|
async createOutboundCall(destination, options = {}) {
|
|
15623
15883
|
const destinationURI = destination instanceof Address ? destination.defaultChannel : destination;
|
|
15884
|
+
let callSession;
|
|
15624
15885
|
try {
|
|
15625
|
-
|
|
15886
|
+
callSession = await this.createCall({
|
|
15626
15887
|
to: destinationURI,
|
|
15627
15888
|
...options
|
|
15628
15889
|
});
|
|
15629
|
-
await (0, import_cjs$5.firstValueFrom)(callSession.selfId$.pipe((0, import_cjs$5.filter)((id) => Boolean(id)), (0, import_cjs$5.take)(1), (0, import_cjs$5.timeout)(this.callCreateTimeout)));
|
|
15890
|
+
await (0, import_cjs$5.firstValueFrom)((0, import_cjs$5.race)(callSession.selfId$.pipe((0, import_cjs$5.filter)((id) => Boolean(id)), (0, import_cjs$5.take)(1), (0, import_cjs$5.timeout)(this.callCreateTimeout)), callSession.errors$.pipe((0, import_cjs$5.take)(1), (0, import_cjs$5.switchMap)((callError) => (0, import_cjs$5.throwError)(() => callError.error)))));
|
|
15630
15891
|
this._calls$.next({
|
|
15631
15892
|
[`${callSession.id}`]: callSession,
|
|
15632
15893
|
...this._calls$.value
|
|
@@ -15634,7 +15895,8 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
15634
15895
|
return callSession;
|
|
15635
15896
|
} catch (error) {
|
|
15636
15897
|
logger$6.error("[Session] Error creating outbound call:", error);
|
|
15637
|
-
|
|
15898
|
+
callSession?.destroy();
|
|
15899
|
+
const callError = new CallCreateError(error instanceof import_cjs$5.TimeoutError ? "Call create timeout" : "Call creation failed", error, "outbound");
|
|
15638
15900
|
this._errors$.next(callError);
|
|
15639
15901
|
throw callError;
|
|
15640
15902
|
}
|
|
@@ -15660,7 +15922,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
15660
15922
|
return callSession;
|
|
15661
15923
|
} catch (error) {
|
|
15662
15924
|
logger$6.error("[Session] Error creating call session:", error);
|
|
15663
|
-
throw new CallCreateError("Call create error", error);
|
|
15925
|
+
throw new CallCreateError("Call create error", error, options.initOffer ? "inbound" : "outbound");
|
|
15664
15926
|
}
|
|
15665
15927
|
}
|
|
15666
15928
|
destroy() {
|
|
@@ -15909,7 +16171,7 @@ var WebSocketController = class WebSocketController extends Destroyable {
|
|
|
15909
16171
|
this.shouldReconnect = false;
|
|
15910
16172
|
this._status$ = this.createBehaviorSubject("disconnected");
|
|
15911
16173
|
this._incomingMessages$ = this.createSubject();
|
|
15912
|
-
this._errors$ = this.
|
|
16174
|
+
this._errors$ = this.createReplaySubject(1);
|
|
15913
16175
|
this.reconnectDelayMin = options.reconnectDelayMin ?? WebSocketController.DEFAULT_RECONNECT_DELAY_MIN_MS;
|
|
15914
16176
|
this.reconnectDelayMax = options.reconnectDelayMax ?? WebSocketController.DEFAULT_RECONNECT_DELAY_MAX_MS;
|
|
15915
16177
|
this.connectionTimeout = options.connectionTimeout ?? WebSocketController.DEFAULT_CONNECTION_TIMEOUT_MS;
|
|
@@ -16060,7 +16322,30 @@ function isSignalwirePingRequest(value) {
|
|
|
16060
16322
|
//#region src/managers/TransportManager.ts
|
|
16061
16323
|
var import_cjs$1 = require_cjs();
|
|
16062
16324
|
const logger$2 = getLogger();
|
|
16063
|
-
var TransportManager = class extends Destroyable {
|
|
16325
|
+
var TransportManager = class TransportManager extends Destroyable {
|
|
16326
|
+
/**
|
|
16327
|
+
* Normalise a server event timestamp to epoch seconds.
|
|
16328
|
+
*
|
|
16329
|
+
* The server uses two formats:
|
|
16330
|
+
* - `webrtc.message`: float epoch seconds (e.g. 1774372099.022817)
|
|
16331
|
+
* - all other events: int epoch microseconds (e.g. 1774372099925857)
|
|
16332
|
+
*
|
|
16333
|
+
* Values above 1e12 are treated as microseconds and divided by 1e6.
|
|
16334
|
+
*/
|
|
16335
|
+
static toEpochSeconds(ts) {
|
|
16336
|
+
const n = typeof ts === "string" ? Number(ts) : ts;
|
|
16337
|
+
return n > 0xe8d4a51000 ? n / 1e6 : n;
|
|
16338
|
+
}
|
|
16339
|
+
/**
|
|
16340
|
+
* Extract the event timestamp from a signalwire.event message.
|
|
16341
|
+
* Returns `null` for messages that have no timestamp
|
|
16342
|
+
* (e.g. signalwire.authorization.state, RPC responses).
|
|
16343
|
+
*/
|
|
16344
|
+
static extractEventTimestamp(message) {
|
|
16345
|
+
if (!isSignalwireRequest(message)) return null;
|
|
16346
|
+
if (message.params.event_type === "signalwire.authorization.state") return null;
|
|
16347
|
+
return TransportManager.toEpochSeconds(message.params.timestamp);
|
|
16348
|
+
}
|
|
16064
16349
|
constructor(storage, protocolKey, webSocketConstructor, relayHost, onError) {
|
|
16065
16350
|
super();
|
|
16066
16351
|
this.storage = storage;
|
|
@@ -16093,6 +16378,23 @@ var TransportManager = class extends Destroyable {
|
|
|
16093
16378
|
return true;
|
|
16094
16379
|
});
|
|
16095
16380
|
};
|
|
16381
|
+
this.discardStaleEvents = () => {
|
|
16382
|
+
return (0, import_cjs$1.filter)((message) => {
|
|
16383
|
+
const ts = TransportManager.extractEventTimestamp(message);
|
|
16384
|
+
if (ts === null) return true;
|
|
16385
|
+
if (this._sessionEpoch === null) {
|
|
16386
|
+
this._sessionEpoch = ts;
|
|
16387
|
+
return true;
|
|
16388
|
+
}
|
|
16389
|
+
if (ts < this._sessionEpoch) {
|
|
16390
|
+
const eventType = isSignalwireRequest(message) ? message.params.event_type : "unknown";
|
|
16391
|
+
logger$2.warn(`[Transport] Discarding stale event: ${eventType} (timestamp=${ts.toFixed(3)}, sessionEpoch=${this._sessionEpoch.toFixed(3)}, delta=${(this._sessionEpoch - ts).toFixed(3)}s)`);
|
|
16392
|
+
return false;
|
|
16393
|
+
}
|
|
16394
|
+
return true;
|
|
16395
|
+
});
|
|
16396
|
+
};
|
|
16397
|
+
this._sessionEpoch = null;
|
|
16096
16398
|
this._outgoingMessages$ = this.createSubject();
|
|
16097
16399
|
this._webSocketConnections = new WebSocketController(webSocketConstructor, relayHost, this._outgoingMessages$.asObservable(), {
|
|
16098
16400
|
connectionTimeout: PreferencesContainer.instance.connectionTimeout,
|
|
@@ -16117,7 +16419,14 @@ var TransportManager = class extends Destroyable {
|
|
|
16117
16419
|
return import_cjs$1.EMPTY;
|
|
16118
16420
|
}), (0, import_cjs$1.share)(), (0, import_cjs$1.takeUntil)(this.destroyed$));
|
|
16119
16421
|
this._jsonRPCResponse$ = this._jsonRPCMessage$.pipe((0, import_cjs$1.filter)(isJSONRPCResponse));
|
|
16120
|
-
this._incomingEvent$ = this._jsonRPCMessage$.pipe(this.ackEvent(), this.replySignalwirePing(), (0, import_cjs$1.filter)((message) => !isJSONRPCResponse(message)), (0, import_cjs$1.share)(), (0, import_cjs$1.takeUntil)(this.destroyed$));
|
|
16422
|
+
this._incomingEvent$ = this._jsonRPCMessage$.pipe(this.ackEvent(), this.replySignalwirePing(), (0, import_cjs$1.filter)((message) => !isJSONRPCResponse(message)), this.discardStaleEvents(), (0, import_cjs$1.share)(), (0, import_cjs$1.takeUntil)(this.destroyed$));
|
|
16423
|
+
}
|
|
16424
|
+
/**
|
|
16425
|
+
* Reset the session epoch. Call this before each signalwire.connect
|
|
16426
|
+
* so that the first event after authentication establishes the new baseline.
|
|
16427
|
+
*/
|
|
16428
|
+
resetSessionEpoch() {
|
|
16429
|
+
this._sessionEpoch = null;
|
|
16121
16430
|
}
|
|
16122
16431
|
async setProtocol(protocol) {
|
|
16123
16432
|
this.protocol$.next(protocol);
|
|
@@ -16236,7 +16545,8 @@ const buildOptionsFromDestination = (destination) => {
|
|
|
16236
16545
|
const channel = new URLSearchParams(queryString).get("channel");
|
|
16237
16546
|
if (channel === "video") return {
|
|
16238
16547
|
audio: true,
|
|
16239
|
-
video: true
|
|
16548
|
+
video: true,
|
|
16549
|
+
receiveVideo: true
|
|
16240
16550
|
};
|
|
16241
16551
|
else if (channel === "audio") return {
|
|
16242
16552
|
audio: true,
|
|
@@ -16266,7 +16576,7 @@ var SignalWire = class extends Destroyable {
|
|
|
16266
16576
|
this._directory$ = this.createBehaviorSubject(void 0);
|
|
16267
16577
|
this._isConnected$ = this.createBehaviorSubject(false);
|
|
16268
16578
|
this._isRegistered$ = this.createBehaviorSubject(false);
|
|
16269
|
-
this._errors$ = this.
|
|
16579
|
+
this._errors$ = this.createReplaySubject(1);
|
|
16270
16580
|
this._options = {};
|
|
16271
16581
|
this._deps = new DependencyContainer();
|
|
16272
16582
|
this._options = {
|
|
@@ -16343,7 +16653,12 @@ var SignalWire = class extends Destroyable {
|
|
|
16343
16653
|
this._subscriber$.next(new Subscriber(this._deps.http));
|
|
16344
16654
|
if (!this._options.skipConnection) await this.connect();
|
|
16345
16655
|
if (!this._options.reconnectAttachedCalls && this._attachManager) await this._attachManager.flush();
|
|
16346
|
-
if (!this._options.skipRegister)
|
|
16656
|
+
if (!this._options.skipRegister) try {
|
|
16657
|
+
await this.register();
|
|
16658
|
+
} catch (error) {
|
|
16659
|
+
logger$1.error("[SignalWire] Registration failed:", error);
|
|
16660
|
+
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16661
|
+
}
|
|
16347
16662
|
this.handleAttachments();
|
|
16348
16663
|
}
|
|
16349
16664
|
async handleAttachments() {
|
|
@@ -16435,7 +16750,7 @@ var SignalWire = class extends Destroyable {
|
|
|
16435
16750
|
* ```
|
|
16436
16751
|
*/
|
|
16437
16752
|
get subscriber$() {
|
|
16438
|
-
return this._subscriber$.asObservable();
|
|
16753
|
+
return this.deferEmission(this._subscriber$.asObservable());
|
|
16439
16754
|
}
|
|
16440
16755
|
/** Current subscriber snapshot, or `undefined` if not yet authenticated. */
|
|
16441
16756
|
get subscriber() {
|
|
@@ -16454,7 +16769,7 @@ var SignalWire = class extends Destroyable {
|
|
|
16454
16769
|
* ```
|
|
16455
16770
|
*/
|
|
16456
16771
|
get directory$() {
|
|
16457
|
-
return this._directory$.asObservable();
|
|
16772
|
+
return this.deferEmission(this._directory$.asObservable());
|
|
16458
16773
|
}
|
|
16459
16774
|
/**
|
|
16460
16775
|
* Current directory snapshot, or `undefined` if the client is not yet connected.
|
|
@@ -16465,7 +16780,7 @@ var SignalWire = class extends Destroyable {
|
|
|
16465
16780
|
}
|
|
16466
16781
|
/** Observable that emits when the subscriber registration state changes. */
|
|
16467
16782
|
get isRegistered$() {
|
|
16468
|
-
return this._isRegistered$.asObservable();
|
|
16783
|
+
return this.deferEmission(this._isRegistered$.asObservable());
|
|
16469
16784
|
}
|
|
16470
16785
|
/** Whether the subscriber is currently registered. */
|
|
16471
16786
|
get isRegistered() {
|
|
@@ -16477,15 +16792,15 @@ var SignalWire = class extends Destroyable {
|
|
|
16477
16792
|
}
|
|
16478
16793
|
/** Observable that emits when the connection state changes. */
|
|
16479
16794
|
get isConnected$() {
|
|
16480
|
-
return this._isConnected$.asObservable();
|
|
16795
|
+
return this.deferEmission(this._isConnected$.asObservable());
|
|
16481
16796
|
}
|
|
16482
16797
|
/** Observable that emits `true` when the client is both connected and authenticated. */
|
|
16483
16798
|
get ready$() {
|
|
16484
|
-
return this.
|
|
16799
|
+
return this.publicCachedObservable("ready$", () => this._isConnected$.pipe((0, import_cjs.switchMap)((connected) => connected ? this._clientSession.authenticated$ : (0, import_cjs.of)(false))));
|
|
16485
16800
|
}
|
|
16486
16801
|
/** Observable stream of errors from transport, authentication, and devices. */
|
|
16487
16802
|
get errors$() {
|
|
16488
|
-
return this._errors$.asObservable();
|
|
16803
|
+
return this.deferEmission(this._errors$.asObservable());
|
|
16489
16804
|
}
|
|
16490
16805
|
/** Disconnects the WebSocket and tears down the session. */
|
|
16491
16806
|
async disconnect() {
|
|
@@ -16506,8 +16821,22 @@ var SignalWire = class extends Destroyable {
|
|
|
16506
16821
|
}));
|
|
16507
16822
|
this._isRegistered$.next(true);
|
|
16508
16823
|
} catch (error) {
|
|
16509
|
-
logger$1.
|
|
16824
|
+
logger$1.debug("[SignalWire] Failed to register subscriber, trying reauthentication...");
|
|
16825
|
+
if (this._deps.credential.token) this._clientSession.reauthenticate(this._deps.credential.token).then(async () => {
|
|
16826
|
+
logger$1.debug("[SignalWire] Reauthentication successful, retrying register()");
|
|
16827
|
+
await this._transport.execute(RPCExecute({
|
|
16828
|
+
method: "subscriber.online",
|
|
16829
|
+
params: {}
|
|
16830
|
+
}));
|
|
16831
|
+
this._isRegistered$.next(true);
|
|
16832
|
+
}).catch((reauthError) => {
|
|
16833
|
+
logger$1.error("[SignalWire] Reauthentication failed during register():", reauthError);
|
|
16834
|
+
const registerError = new InvalidCredentialsError("Failed to register subscriber, and reauthentication attempt also failed. Please check your credentials.", { cause: reauthError instanceof Error ? reauthError : new Error(String(reauthError), { cause: reauthError }) });
|
|
16835
|
+
this._errors$.next(registerError);
|
|
16836
|
+
throw registerError;
|
|
16837
|
+
});
|
|
16510
16838
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
16839
|
+
throw error;
|
|
16511
16840
|
}
|
|
16512
16841
|
}
|
|
16513
16842
|
/** Unregisters the subscriber, going offline for inbound calls. */
|
|
@@ -16546,7 +16875,7 @@ var SignalWire = class extends Destroyable {
|
|
|
16546
16875
|
}
|
|
16547
16876
|
/** Observable list of available audio input (microphone) devices. */
|
|
16548
16877
|
get audioInputDevices$() {
|
|
16549
|
-
return this._deviceController.audioInputDevices
|
|
16878
|
+
return this.deferEmission(this._deviceController.audioInputDevices$);
|
|
16550
16879
|
}
|
|
16551
16880
|
/** Current snapshot of available audio input devices. */
|
|
16552
16881
|
get audioInputDevices() {
|
|
@@ -16554,7 +16883,7 @@ var SignalWire = class extends Destroyable {
|
|
|
16554
16883
|
}
|
|
16555
16884
|
/** Observable list of available audio output (speaker) devices. */
|
|
16556
16885
|
get audioOutputDevices$() {
|
|
16557
|
-
return this._deviceController.audioOutputDevices
|
|
16886
|
+
return this.deferEmission(this._deviceController.audioOutputDevices$);
|
|
16558
16887
|
}
|
|
16559
16888
|
/** Current snapshot of available audio output devices. */
|
|
16560
16889
|
get audioOutputDevices() {
|
|
@@ -16562,7 +16891,7 @@ var SignalWire = class extends Destroyable {
|
|
|
16562
16891
|
}
|
|
16563
16892
|
/** Observable list of available video input (camera) devices. */
|
|
16564
16893
|
get videoInputDevices$() {
|
|
16565
|
-
return this._deviceController.videoInputDevices
|
|
16894
|
+
return this.deferEmission(this._deviceController.videoInputDevices$);
|
|
16566
16895
|
}
|
|
16567
16896
|
/** Current snapshot of available video input devices. */
|
|
16568
16897
|
get videoInputDevices() {
|
|
@@ -16570,15 +16899,15 @@ var SignalWire = class extends Destroyable {
|
|
|
16570
16899
|
}
|
|
16571
16900
|
/** Observable of the currently selected audio input device. */
|
|
16572
16901
|
get selectedAudioInputDevice$() {
|
|
16573
|
-
return this._deviceController.selectedAudioInputDevice
|
|
16902
|
+
return this.deferEmission(this._deviceController.selectedAudioInputDevice$);
|
|
16574
16903
|
}
|
|
16575
16904
|
/** Observable of the currently selected audio output device. */
|
|
16576
16905
|
get selectedAudioOutputDevice$() {
|
|
16577
|
-
return this._deviceController.selectedAudioOutputDevice
|
|
16906
|
+
return this.deferEmission(this._deviceController.selectedAudioOutputDevice$);
|
|
16578
16907
|
}
|
|
16579
16908
|
/** Observable of the currently selected video input device. */
|
|
16580
16909
|
get selectedVideoInputDevice$() {
|
|
16581
|
-
return this._deviceController.selectedVideoInputDevice
|
|
16910
|
+
return this.deferEmission(this._deviceController.selectedVideoInputDevice$);
|
|
16582
16911
|
}
|
|
16583
16912
|
/** Currently selected audio input device, or `null` if none. */
|
|
16584
16913
|
get selectedAudioInputDevice() {
|