@signalwire/js 4.0.0-beta.7 → 4.0.0-beta.8
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-BxFSgMTI.d.cts +30 -0
- package/dist/{base-A5AZTrAd.d.cts.map → base-BxFSgMTI.d.cts.map} +1 -1
- package/dist/base-DKDZK4Rr.d.mts +30 -0
- package/dist/{base-aVtoG8Wk.d.mts.map → base-DKDZK4Rr.d.mts.map} +1 -1
- package/dist/browser.mjs +337 -121
- package/dist/browser.mjs.map +1 -1
- package/dist/browser.umd.js +337 -121
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +315 -109
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +276 -153
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +276 -153
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +316 -110
- 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-BHQMSEzq.mjs → operators-C8Tqm86j.mjs} +13 -3
- package/dist/operators-C8Tqm86j.mjs.map +1 -0
- package/dist/{operators-DT4UB24-.cjs → operators-CJEML6aa.cjs} +18 -2
- package/dist/operators-CJEML6aa.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/base-A5AZTrAd.d.cts +0 -23
- package/dist/base-aVtoG8Wk.d.mts +0 -23
- package/dist/operators-BHQMSEzq.mjs.map +0 -1
- package/dist/operators-DT4UB24-.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_operators = require('./operators-
|
|
1
|
+
const require_operators = require('./operators-CJEML6aa.cjs');
|
|
2
2
|
let jwt_decode = require("jwt-decode");
|
|
3
3
|
let rxjs = require("rxjs");
|
|
4
4
|
let uuid = require("uuid");
|
|
@@ -295,7 +295,7 @@ var PreferencesContainer = class PreferencesContainer {
|
|
|
295
295
|
skipDeviceMonitoring: false,
|
|
296
296
|
savePreferences: false
|
|
297
297
|
};
|
|
298
|
-
this.receiveVideo =
|
|
298
|
+
this.receiveVideo = false;
|
|
299
299
|
this.receiveAudio = true;
|
|
300
300
|
this.preferredAudioInput = null;
|
|
301
301
|
this.preferredAudioOutput = null;
|
|
@@ -607,7 +607,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
607
607
|
};
|
|
608
608
|
this._devicesState$ = this.createBehaviorSubject(initialDevicesState);
|
|
609
609
|
this._selectedDevicesState$ = this.createBehaviorSubject(initialSelectedDevicesState);
|
|
610
|
-
this._errors$ = this.
|
|
610
|
+
this._errors$ = this.createReplaySubject(1);
|
|
611
611
|
this.init();
|
|
612
612
|
}
|
|
613
613
|
get selectedAudioInputDeviceConstraints() {
|
|
@@ -1087,7 +1087,7 @@ const RPCExecute = ({ method, params }) => {
|
|
|
1087
1087
|
|
|
1088
1088
|
//#endregion
|
|
1089
1089
|
//#region src/core/RPCMessages/VertoMessages.ts
|
|
1090
|
-
const
|
|
1090
|
+
const SDK_TO_VERTO_FIELD_MAP = {
|
|
1091
1091
|
id: "callID",
|
|
1092
1092
|
destinationNumber: "destination_number",
|
|
1093
1093
|
remoteCallerName: "remote_caller_id_name",
|
|
@@ -1096,19 +1096,31 @@ const tmpMap = {
|
|
|
1096
1096
|
callerNumber: "caller_id_number",
|
|
1097
1097
|
fromCallAddressId: "from_fabric_address_id"
|
|
1098
1098
|
};
|
|
1099
|
+
const EXCLUDED_DIALOG_PARAMS = new Set([
|
|
1100
|
+
"remoteSdp",
|
|
1101
|
+
"localStream",
|
|
1102
|
+
"remoteStream"
|
|
1103
|
+
]);
|
|
1099
1104
|
/**
|
|
1100
|
-
* Translate SDK fields into verto variables
|
|
1105
|
+
* Translate SDK fields into verto variables.
|
|
1106
|
+
* Returns a new object — the input is never mutated.
|
|
1101
1107
|
*/
|
|
1108
|
+
/** @internal Exported for testing only. */
|
|
1102
1109
|
const filterVertoParams = (params) => {
|
|
1103
|
-
if (Object.prototype.hasOwnProperty.call(params, "dialogParams"))
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1110
|
+
if (!Object.prototype.hasOwnProperty.call(params, "dialogParams")) return params;
|
|
1111
|
+
const sourceDialogParams = params.dialogParams;
|
|
1112
|
+
const filteredDialogParams = Object.entries(sourceDialogParams).reduce((acc, [key, value]) => {
|
|
1113
|
+
if (EXCLUDED_DIALOG_PARAMS.has(key)) return acc;
|
|
1114
|
+
const mappedKey = SDK_TO_VERTO_FIELD_MAP[key] ?? key;
|
|
1115
|
+
return {
|
|
1116
|
+
...acc,
|
|
1117
|
+
[mappedKey]: value
|
|
1118
|
+
};
|
|
1119
|
+
}, {});
|
|
1120
|
+
return {
|
|
1121
|
+
...params,
|
|
1122
|
+
dialogParams: filteredDialogParams
|
|
1123
|
+
};
|
|
1112
1124
|
};
|
|
1113
1125
|
const buildVertoRPCMessage = (method) => {
|
|
1114
1126
|
return (params = {}) => {
|
|
@@ -1759,7 +1771,13 @@ var Participant = class extends Destroyable {
|
|
|
1759
1771
|
}
|
|
1760
1772
|
/** Removes this participant from the call. */
|
|
1761
1773
|
async remove() {
|
|
1762
|
-
|
|
1774
|
+
const state = this._state$.value;
|
|
1775
|
+
const target = {
|
|
1776
|
+
member_id: this.id,
|
|
1777
|
+
call_id: state.call_id ?? "",
|
|
1778
|
+
node_id: state.node_id ?? ""
|
|
1779
|
+
};
|
|
1780
|
+
await this.executeMethod(target, "call.member.remove", {});
|
|
1763
1781
|
}
|
|
1764
1782
|
/** Ends the call for this participant. */
|
|
1765
1783
|
async end() {
|
|
@@ -2001,7 +2019,6 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2001
2019
|
this.options = options;
|
|
2002
2020
|
this.callIds = /* @__PURE__ */ new Set();
|
|
2003
2021
|
this.roomSessionIds = /* @__PURE__ */ new Set();
|
|
2004
|
-
this._status$ = this.createBehaviorSubject("trying");
|
|
2005
2022
|
this._participants$ = this.createBehaviorSubject({});
|
|
2006
2023
|
this._self$ = this.createBehaviorSubject(null);
|
|
2007
2024
|
this._sessionState$ = this.createBehaviorSubject(initialSessionState);
|
|
@@ -2010,15 +2027,12 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2010
2027
|
get participants$() {
|
|
2011
2028
|
return this.cachedObservable("participants$", () => this._participants$.asObservable().pipe((0, rxjs.map)((participantsRecord) => Object.values(participantsRecord))));
|
|
2012
2029
|
}
|
|
2030
|
+
get participants() {
|
|
2031
|
+
return Object.values(this._participants$.value);
|
|
2032
|
+
}
|
|
2013
2033
|
get self$() {
|
|
2014
2034
|
return this.cachedObservable("self$", () => this._self$.asObservable().pipe(require_operators.filterNull()));
|
|
2015
2035
|
}
|
|
2016
|
-
get status$() {
|
|
2017
|
-
return this._status$.asObservable();
|
|
2018
|
-
}
|
|
2019
|
-
get status() {
|
|
2020
|
-
return this._status$.value;
|
|
2021
|
-
}
|
|
2022
2036
|
isRoomSessionIdValid(roomSessionId) {
|
|
2023
2037
|
return this.roomSessionIds.has(roomSessionId);
|
|
2024
2038
|
}
|
|
@@ -2103,7 +2117,6 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2103
2117
|
callId: callJoinedEvent.call_id,
|
|
2104
2118
|
roomSessionId: callJoinedEvent.room_session_id
|
|
2105
2119
|
});
|
|
2106
|
-
this._status$.next("connected");
|
|
2107
2120
|
const sessionState = callJoinedEvent.room_session;
|
|
2108
2121
|
const { capabilities } = callJoinedEvent;
|
|
2109
2122
|
this.selfId = this.selfId ?? callJoinedEvent.member_id;
|
|
@@ -2230,12 +2243,53 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2230
2243
|
|
|
2231
2244
|
//#endregion
|
|
2232
2245
|
//#region src/helpers/SDPHelper.ts
|
|
2246
|
+
/** Valid SDP direction attribute values. */
|
|
2247
|
+
const SDP_DIRECTIONS = new Set([
|
|
2248
|
+
"sendrecv",
|
|
2249
|
+
"sendonly",
|
|
2250
|
+
"recvonly",
|
|
2251
|
+
"inactive"
|
|
2252
|
+
]);
|
|
2233
2253
|
/**
|
|
2234
|
-
*
|
|
2254
|
+
* Extracts the media directions (audio/video) from an SDP string.
|
|
2255
|
+
*
|
|
2256
|
+
* Parses each media section (`m=audio` / `m=video`) and reads the `a=` direction
|
|
2257
|
+
* attribute (`sendrecv`, `sendonly`, `recvonly`, `inactive`).
|
|
2258
|
+
* If no explicit direction attribute is found for a media section, defaults to `sendrecv`
|
|
2259
|
+
* per RFC 4566.
|
|
2235
2260
|
*
|
|
2236
|
-
*
|
|
2237
|
-
*
|
|
2261
|
+
* @param sdp - The SDP string to parse
|
|
2262
|
+
* @returns The extracted audio and video directions
|
|
2263
|
+
*
|
|
2264
|
+
* @example
|
|
2265
|
+
* ```typescript
|
|
2266
|
+
* 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`;
|
|
2267
|
+
* extractMediaDirectionsFromSDP(sdp);
|
|
2268
|
+
* // { audio: 'sendrecv', video: 'recvonly' }
|
|
2269
|
+
* ```
|
|
2238
2270
|
*/
|
|
2271
|
+
function extractMediaDirectionsFromSDP(sdp) {
|
|
2272
|
+
const result = {
|
|
2273
|
+
audio: "inactive",
|
|
2274
|
+
video: "inactive"
|
|
2275
|
+
};
|
|
2276
|
+
if (!sdp) return result;
|
|
2277
|
+
const lines = sdp.split(/\r?\n/);
|
|
2278
|
+
let currentMediaKind = null;
|
|
2279
|
+
let currentDirection = null;
|
|
2280
|
+
for (const line of lines) if (line.startsWith("m=")) {
|
|
2281
|
+
if (currentMediaKind) result[currentMediaKind] = currentDirection ?? "sendrecv";
|
|
2282
|
+
if (line.startsWith("m=audio")) currentMediaKind = "audio";
|
|
2283
|
+
else if (line.startsWith("m=video")) currentMediaKind = "video";
|
|
2284
|
+
else currentMediaKind = null;
|
|
2285
|
+
currentDirection = null;
|
|
2286
|
+
} else if (currentMediaKind && line.startsWith("a=")) {
|
|
2287
|
+
const attr = line.substring(2).trim();
|
|
2288
|
+
if (SDP_DIRECTIONS.has(attr)) currentDirection = attr;
|
|
2289
|
+
}
|
|
2290
|
+
if (currentMediaKind) result[currentMediaKind] = currentDirection ?? "sendrecv";
|
|
2291
|
+
return result;
|
|
2292
|
+
}
|
|
2239
2293
|
/**
|
|
2240
2294
|
* Validates that an SDP string has at least one non-host ICE candidate
|
|
2241
2295
|
* for each media section (m= line).
|
|
@@ -2536,6 +2590,15 @@ var LocalStreamController = class extends Destroyable {
|
|
|
2536
2590
|
track.addEventListener("ended", this.mediaTrackEndedHandler);
|
|
2537
2591
|
}
|
|
2538
2592
|
/**
|
|
2593
|
+
* Update the controller options (e.g., when media overrides are applied).
|
|
2594
|
+
*/
|
|
2595
|
+
updateOptions(options) {
|
|
2596
|
+
this.options = {
|
|
2597
|
+
...this.options,
|
|
2598
|
+
...options
|
|
2599
|
+
};
|
|
2600
|
+
}
|
|
2601
|
+
/**
|
|
2539
2602
|
* Stop all local tracks and clean up.
|
|
2540
2603
|
*/
|
|
2541
2604
|
stopAllTracks() {
|
|
@@ -2873,11 +2936,12 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
2873
2936
|
this._connectionState$ = this.createReplaySubject(1);
|
|
2874
2937
|
this._signalingState$ = this.createReplaySubject(1);
|
|
2875
2938
|
this._iceGatheringState$ = this.createReplaySubject(1);
|
|
2876
|
-
this._errors$ = this.
|
|
2939
|
+
this._errors$ = this.createReplaySubject(1);
|
|
2877
2940
|
this._iceCandidates$ = this.createReplaySubject(1);
|
|
2878
2941
|
this._initialized$ = this.createReplaySubject(1);
|
|
2879
2942
|
this._remoteDescription$ = this.createReplaySubject(1);
|
|
2880
2943
|
this._remoteStream$ = this.createBehaviorSubject(null);
|
|
2944
|
+
this._remoteOfferMediaDirections = null;
|
|
2881
2945
|
this.deviceController = deviceController ?? {};
|
|
2882
2946
|
this.id = options.callId ?? (0, uuid.v4)();
|
|
2883
2947
|
this._type = remoteSessionDescription ? "answer" : "offer";
|
|
@@ -2885,10 +2949,19 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
2885
2949
|
type: "offer",
|
|
2886
2950
|
sdp: remoteSessionDescription
|
|
2887
2951
|
} : void 0;
|
|
2952
|
+
this._remoteOfferMediaDirections = remoteSessionDescription ? extractMediaDirectionsFromSDP(remoteSessionDescription) : null;
|
|
2953
|
+
const offerDefaults = this._remoteOfferMediaDirections ? {
|
|
2954
|
+
audio: this._remoteOfferMediaDirections.audio.includes("recv"),
|
|
2955
|
+
video: this._remoteOfferMediaDirections.video.includes("recv"),
|
|
2956
|
+
receiveAudio: this._remoteOfferMediaDirections.audio.includes("send"),
|
|
2957
|
+
receiveVideo: this._remoteOfferMediaDirections.video.includes("send")
|
|
2958
|
+
} : {};
|
|
2888
2959
|
this.options = {
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2960
|
+
...options,
|
|
2961
|
+
audio: options.audio ?? offerDefaults.audio,
|
|
2962
|
+
video: options.video ?? offerDefaults.video,
|
|
2963
|
+
receiveAudio: options.receiveAudio ?? offerDefaults.receiveAudio ?? PreferencesContainer.instance.receiveAudio,
|
|
2964
|
+
receiveVideo: options.receiveVideo ?? offerDefaults.receiveVideo ?? PreferencesContainer.instance.receiveVideo
|
|
2892
2965
|
};
|
|
2893
2966
|
this.localStreamController = new LocalStreamController({
|
|
2894
2967
|
propose: this.propose,
|
|
@@ -3033,7 +3106,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3033
3106
|
};
|
|
3034
3107
|
}
|
|
3035
3108
|
get inputVideoDeviceConstraints() {
|
|
3036
|
-
if (this.options.video
|
|
3109
|
+
if (!this.options.video && !this.options.inputVideoDeviceConstraints) return false;
|
|
3037
3110
|
return {
|
|
3038
3111
|
...this.options.inputVideoDeviceConstraints,
|
|
3039
3112
|
...this.deviceController.selectedVideoInputDeviceConstraints
|
|
@@ -3055,12 +3128,12 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3055
3128
|
default: return {
|
|
3056
3129
|
...options,
|
|
3057
3130
|
offerToReceiveAudio: true,
|
|
3058
|
-
offerToReceiveVideo: Boolean(this.inputVideoDeviceConstraints)
|
|
3131
|
+
offerToReceiveVideo: this.options.receiveVideo ?? Boolean(this.inputVideoDeviceConstraints)
|
|
3059
3132
|
};
|
|
3060
3133
|
}
|
|
3061
3134
|
}
|
|
3062
3135
|
get answerOptions() {
|
|
3063
|
-
return {};
|
|
3136
|
+
return { iceRestart: this.firstSDPExchangeCompleted ? true : void 0 };
|
|
3064
3137
|
}
|
|
3065
3138
|
/**
|
|
3066
3139
|
* Initialize the RTCPeerConnection and setup event listeners.
|
|
@@ -3095,11 +3168,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3095
3168
|
});
|
|
3096
3169
|
await this.updateSelectedInputDevice(kind, deviceInfo);
|
|
3097
3170
|
});
|
|
3098
|
-
await this.setupTrackHandling();
|
|
3099
|
-
this._initialized$.next(true);
|
|
3100
3171
|
if (this.type === "answer" && this.sdpInit) {
|
|
3172
|
+
await this.setupRemoteTracks();
|
|
3173
|
+
this._initialized$.next(true);
|
|
3101
3174
|
this.setupEventListeners();
|
|
3102
|
-
|
|
3175
|
+
this._isNegotiating$.next(true);
|
|
3176
|
+
await this._setRemoteDescription(this.sdpInit);
|
|
3177
|
+
} else {
|
|
3178
|
+
await this.setupTrackHandling();
|
|
3179
|
+
this._initialized$.next(true);
|
|
3103
3180
|
}
|
|
3104
3181
|
} catch (error) {
|
|
3105
3182
|
logger$11.error("[RTCPeerConnectionController] Initialization error:", error);
|
|
@@ -3197,6 +3274,35 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3197
3274
|
default:
|
|
3198
3275
|
}
|
|
3199
3276
|
}
|
|
3277
|
+
/**
|
|
3278
|
+
* Accept an inbound call by creating the SDP answer.
|
|
3279
|
+
* Optionally override media options before the answer is generated.
|
|
3280
|
+
* Must be called after initialization for inbound (answer-type) connections.
|
|
3281
|
+
*/
|
|
3282
|
+
async acceptInbound(mediaOverrides) {
|
|
3283
|
+
if (mediaOverrides) {
|
|
3284
|
+
const { audio, video, receiveAudio, receiveVideo } = mediaOverrides;
|
|
3285
|
+
this.options = {
|
|
3286
|
+
...this.options,
|
|
3287
|
+
...audio !== void 0 ? { audio } : {},
|
|
3288
|
+
...video !== void 0 ? { video } : {},
|
|
3289
|
+
...receiveAudio !== void 0 ? { receiveAudio } : {},
|
|
3290
|
+
...receiveVideo !== void 0 ? { receiveVideo } : {}
|
|
3291
|
+
};
|
|
3292
|
+
this.transceiverController?.updateOptions({
|
|
3293
|
+
receiveAudio: this.receiveAudio,
|
|
3294
|
+
receiveVideo: this.receiveVideo
|
|
3295
|
+
});
|
|
3296
|
+
this.localStreamController.updateOptions({
|
|
3297
|
+
inputAudioDeviceConstraints: this.inputAudioDeviceConstraints,
|
|
3298
|
+
inputVideoDeviceConstraints: this.inputVideoDeviceConstraints
|
|
3299
|
+
});
|
|
3300
|
+
}
|
|
3301
|
+
await this.setupLocalTracks();
|
|
3302
|
+
const { answerOptions } = this;
|
|
3303
|
+
logger$11.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
|
|
3304
|
+
await this.createAnswer(answerOptions);
|
|
3305
|
+
}
|
|
3200
3306
|
async handleOfferReceived() {
|
|
3201
3307
|
if (!this.sdpInit) throw new require_operators.DependencyError("SDP initialization parameters are not set");
|
|
3202
3308
|
this._isNegotiating$.next(true);
|
|
@@ -3271,37 +3377,29 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3271
3377
|
}
|
|
3272
3378
|
async setupLocalTracks() {
|
|
3273
3379
|
logger$11.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
|
|
3274
|
-
|
|
3275
|
-
if (
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
if (localStream) {
|
|
3282
|
-
if (this.transceiverController?.useAddStream ?? false) {
|
|
3283
|
-
logger$11.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
|
|
3284
|
-
this.peerConnection?.addStream(localStream);
|
|
3285
|
-
if (!this.isNegotiating) {
|
|
3286
|
-
logger$11.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
|
|
3287
|
-
this.negotiationNeeded$.next();
|
|
3288
|
-
}
|
|
3289
|
-
return;
|
|
3380
|
+
const localStream = this.localStream ?? await this.localStreamController.buildLocalStream();
|
|
3381
|
+
if (this.transceiverController?.useAddStream ?? false) {
|
|
3382
|
+
logger$11.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
|
|
3383
|
+
this.peerConnection?.addStream(localStream);
|
|
3384
|
+
if (!this.isNegotiating) {
|
|
3385
|
+
logger$11.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
|
|
3386
|
+
this.negotiationNeeded$.next();
|
|
3290
3387
|
}
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
}
|
|
3388
|
+
return;
|
|
3389
|
+
}
|
|
3390
|
+
for (const kind of ["audio", "video"]) {
|
|
3391
|
+
const tracks = (kind === "audio" ? localStream.getAudioTracks() : localStream.getVideoTracks()).map((track, index) => ({
|
|
3392
|
+
index,
|
|
3393
|
+
track
|
|
3394
|
+
}));
|
|
3395
|
+
for (const { index, track } of tracks) {
|
|
3396
|
+
this.localStreamController.addTrackEndedListener(track);
|
|
3397
|
+
if (this.transceiverController?.useAddTransceivers ?? false) {
|
|
3398
|
+
const transceivers = (kind === "audio" ? this.transceiverController?.audioTransceivers : this.transceiverController?.videoTransceivers) ?? [];
|
|
3399
|
+
await this.transceiverController?.setupTransceiverSender(track, localStream, transceivers[index]);
|
|
3400
|
+
} else {
|
|
3401
|
+
logger$11.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
|
|
3402
|
+
this.peerConnection?.addTrack(track, localStream);
|
|
3305
3403
|
}
|
|
3306
3404
|
}
|
|
3307
3405
|
}
|
|
@@ -3318,7 +3416,12 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3318
3416
|
if (!this.peerConnection) throw new require_operators.DependencyError("RTCPeerConnection is not initialized");
|
|
3319
3417
|
this.peerConnection.ontrack = (event) => {
|
|
3320
3418
|
logger$11.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
|
|
3321
|
-
this._remoteStream$.next(event.streams[0]);
|
|
3419
|
+
if (event.streams[0]) this._remoteStream$.next(event.streams[0]);
|
|
3420
|
+
else {
|
|
3421
|
+
const existingTracks = this._remoteStream$.value?.getTracks() ?? [];
|
|
3422
|
+
const newStream = new MediaStream([...existingTracks, event.track]);
|
|
3423
|
+
this._remoteStream$.next(newStream);
|
|
3424
|
+
}
|
|
3322
3425
|
};
|
|
3323
3426
|
await this.transceiverController?.setupRemoteTransceivers(this.type);
|
|
3324
3427
|
}
|
|
@@ -3417,7 +3520,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3417
3520
|
});
|
|
3418
3521
|
}
|
|
3419
3522
|
get mediaDirections() {
|
|
3420
|
-
return this.transceiverController?.getMediaDirections() ?? {
|
|
3523
|
+
return this.transceiverController?.getMediaDirections() ?? this._remoteOfferMediaDirections ?? {
|
|
3421
3524
|
audio: "inactive",
|
|
3422
3525
|
video: "inactive"
|
|
3423
3526
|
};
|
|
@@ -3576,6 +3679,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3576
3679
|
});
|
|
3577
3680
|
this.subscribeTo(this.vertoAnswer$, (event) => {
|
|
3578
3681
|
logger$10.debug("[WebRTCManager] Received Verto answer event:", event);
|
|
3682
|
+
this._signalingStatus$.next("connecting");
|
|
3579
3683
|
const { sdp, callID } = event;
|
|
3580
3684
|
this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
|
|
3581
3685
|
status: "received",
|
|
@@ -3647,13 +3751,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3647
3751
|
if (response.error) {
|
|
3648
3752
|
const error = new require_operators.JSONRPCError(response.error.code, response.error.message, response.error.data);
|
|
3649
3753
|
this.onError?.(error);
|
|
3650
|
-
|
|
3754
|
+
return response;
|
|
3651
3755
|
}
|
|
3652
3756
|
const innerResult = require_operators.getValueFrom(response, "result.result");
|
|
3653
3757
|
if (innerResult?.error) {
|
|
3654
3758
|
const error = new require_operators.JSONRPCError(innerResult.error.code, innerResult.error.message, innerResult.error.data);
|
|
3655
3759
|
this.onError?.(error);
|
|
3656
|
-
|
|
3760
|
+
return response;
|
|
3657
3761
|
}
|
|
3658
3762
|
return response;
|
|
3659
3763
|
}
|
|
@@ -3673,7 +3777,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3673
3777
|
}
|
|
3674
3778
|
} catch (error) {
|
|
3675
3779
|
logger$10.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
|
|
3676
|
-
|
|
3780
|
+
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
3677
3781
|
}
|
|
3678
3782
|
}
|
|
3679
3783
|
async processModifyResponse(response, rtcPeerConnController) {
|
|
@@ -3687,12 +3791,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3687
3791
|
});
|
|
3688
3792
|
} catch (error) {
|
|
3689
3793
|
logger$10.warn("[WebRTCManager] Error processing modify response:", error);
|
|
3690
|
-
|
|
3794
|
+
const modifyError = error instanceof Error ? error : new Error(String(error), { cause: error });
|
|
3795
|
+
this.onError?.(modifyError);
|
|
3691
3796
|
}
|
|
3692
3797
|
}
|
|
3693
3798
|
}
|
|
3694
3799
|
processInviteResponse(response, rtcPeerConnController) {
|
|
3695
3800
|
if (!response.error && require_operators.getValueFrom(response, "result.result.result.message") === "CALL CREATED") {
|
|
3801
|
+
this._signalingStatus$.next("trying");
|
|
3696
3802
|
this._nodeId$.next(require_operators.getValueFrom(response, "result.node_id") ?? null);
|
|
3697
3803
|
const memberId = require_operators.getValueFrom(response, "result.result.result.memberID") ?? null;
|
|
3698
3804
|
const callId = require_operators.getValueFrom(response, "result.result.result.callID") ?? null;
|
|
@@ -3747,6 +3853,36 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3747
3853
|
this.subscribeTo(rtcPeerConnController.errors$, (error) => {
|
|
3748
3854
|
this.onError?.(error);
|
|
3749
3855
|
});
|
|
3856
|
+
if (options.initOffer) this.handleInboundAnswer(rtcPeerConnController);
|
|
3857
|
+
}
|
|
3858
|
+
async handleInboundAnswer(rtcPeerConnController) {
|
|
3859
|
+
logger$10.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
|
|
3860
|
+
const vertoByeOrAccepted = await (0, rxjs.firstValueFrom)((0, rxjs.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, rxjs.takeUntil)(this.destroyed$))).catch(() => null);
|
|
3861
|
+
if (vertoByeOrAccepted === null) {
|
|
3862
|
+
logger$10.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
|
|
3863
|
+
return;
|
|
3864
|
+
}
|
|
3865
|
+
if (isVertoByeMessage(vertoByeOrAccepted)) {
|
|
3866
|
+
logger$10.info("[WebRTCManager] Inbound call ended by remote before answer.");
|
|
3867
|
+
this.callSession?.destroy();
|
|
3868
|
+
} else if (!vertoByeOrAccepted) {
|
|
3869
|
+
logger$10.info("[WebRTCManager] Inbound call rejected by user.");
|
|
3870
|
+
try {
|
|
3871
|
+
await this.bye("USER_BUSY");
|
|
3872
|
+
} finally {
|
|
3873
|
+
this._signalingStatus$.next("disconnected");
|
|
3874
|
+
this.callSession?.destroy();
|
|
3875
|
+
}
|
|
3876
|
+
} else {
|
|
3877
|
+
logger$10.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
|
|
3878
|
+
const answerOptions = this.webRtcCallSession.answerMediaOptions;
|
|
3879
|
+
try {
|
|
3880
|
+
await rtcPeerConnController.acceptInbound(answerOptions);
|
|
3881
|
+
} catch (error) {
|
|
3882
|
+
logger$10.error("[WebRTCManager] Error creating inbound answer:", error);
|
|
3883
|
+
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3750
3886
|
}
|
|
3751
3887
|
setupVertoAttachHandler() {
|
|
3752
3888
|
this.subscribeTo(this.vertoAttach$, async (vertoAttach) => {
|
|
@@ -3764,7 +3900,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3764
3900
|
});
|
|
3765
3901
|
}
|
|
3766
3902
|
initObservables(rtcPeerConnController) {
|
|
3767
|
-
this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, rxjs.filter)((state) => state === "connected"), (0, rxjs.
|
|
3903
|
+
this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, rxjs.filter)((state) => state === "connected"), (0, rxjs.map)(() => rtcPeerConnController.mediaDirections), (0, rxjs.startWith)(rtcPeerConnController.mediaDirections), (0, rxjs.takeUntil)(this.destroyed$));
|
|
3768
3904
|
this.localStream$ = rtcPeerConnController.localStream$.pipe(require_operators.filterNull(), (0, rxjs.takeUntil)(this.destroyed$));
|
|
3769
3905
|
this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(require_operators.filterNull(), (0, rxjs.takeUntil)(this.destroyed$));
|
|
3770
3906
|
}
|
|
@@ -3780,7 +3916,6 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3780
3916
|
});
|
|
3781
3917
|
this.sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnController);
|
|
3782
3918
|
} else if (initial) {
|
|
3783
|
-
this._signalingStatus$.next("trying");
|
|
3784
3919
|
const vertoMessageRequest = VertoInvite({
|
|
3785
3920
|
dialogParams,
|
|
3786
3921
|
sdp
|
|
@@ -4086,8 +4221,8 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4086
4221
|
this.clientSession = clientSession;
|
|
4087
4222
|
this.options = options;
|
|
4088
4223
|
this.address = address;
|
|
4089
|
-
this.
|
|
4090
|
-
this.
|
|
4224
|
+
this._errors$ = this.createReplaySubject(1);
|
|
4225
|
+
this._lastMergedStatus = "new";
|
|
4091
4226
|
this._answered$ = this.createReplaySubject();
|
|
4092
4227
|
this._holdState = false;
|
|
4093
4228
|
this._userVariables$ = this.createBehaviorSubject({ ...PreferencesContainer.instance.userVariables });
|
|
@@ -4108,8 +4243,10 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4108
4243
|
const managers = initialization.initializeManagers(this);
|
|
4109
4244
|
this.vertoManager = managers.vertoManager;
|
|
4110
4245
|
this.callEventsManager = managers.callEventsManager;
|
|
4111
|
-
if (options.initOffer)
|
|
4112
|
-
|
|
4246
|
+
if (options.initOffer) {
|
|
4247
|
+
this._status$ = this.createBehaviorSubject("ringing");
|
|
4248
|
+
this._lastMergedStatus = "ringing";
|
|
4249
|
+
} else this._status$ = this.createBehaviorSubject("new");
|
|
4113
4250
|
const { deviceController } = initialization;
|
|
4114
4251
|
this.participantFactory = new ParticipantFactory(this.executeMethod.bind(this), this.vertoManager, deviceController);
|
|
4115
4252
|
}
|
|
@@ -4117,9 +4254,17 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4117
4254
|
get errors$() {
|
|
4118
4255
|
return this._errors$.asObservable();
|
|
4119
4256
|
}
|
|
4120
|
-
/**
|
|
4121
|
-
|
|
4122
|
-
|
|
4257
|
+
/**
|
|
4258
|
+
* @internal Push an error to the call's error stream.
|
|
4259
|
+
* Fatal errors automatically transition the call to `'failed'` and destroy it.
|
|
4260
|
+
*/
|
|
4261
|
+
emitError(callError) {
|
|
4262
|
+
if (this._status$.value === "destroyed" || this._status$.value === "failed") return;
|
|
4263
|
+
this._errors$.next(callError);
|
|
4264
|
+
if (callError.fatal) {
|
|
4265
|
+
this._status$.next("failed");
|
|
4266
|
+
this.destroy();
|
|
4267
|
+
}
|
|
4123
4268
|
}
|
|
4124
4269
|
/** Whether this call is `'inbound'` or `'outbound'`. */
|
|
4125
4270
|
get direction() {
|
|
@@ -4159,7 +4304,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4159
4304
|
}
|
|
4160
4305
|
/** Current snapshot of all participants in the call. */
|
|
4161
4306
|
get participants() {
|
|
4162
|
-
return
|
|
4307
|
+
return this.callEventsManager.participants;
|
|
4163
4308
|
}
|
|
4164
4309
|
/** The local participant, or `null` if not yet joined. */
|
|
4165
4310
|
get self() {
|
|
@@ -4168,7 +4313,6 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4168
4313
|
async toggleLock() {
|
|
4169
4314
|
const method = this.locked ? "call.unlock" : "call.lock";
|
|
4170
4315
|
await this.executeMethod(this.selfId ?? "", method, {});
|
|
4171
|
-
throw new require_operators.UnimplementedError();
|
|
4172
4316
|
}
|
|
4173
4317
|
async toggleHold() {
|
|
4174
4318
|
if (this._holdState) await this.vertoManager.unhold();
|
|
@@ -4210,25 +4354,31 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4210
4354
|
}
|
|
4211
4355
|
}
|
|
4212
4356
|
buildMethodParams(target, args) {
|
|
4213
|
-
const
|
|
4214
|
-
node_id: this.nodeId,
|
|
4215
|
-
call_id: this.id
|
|
4357
|
+
const self = {
|
|
4358
|
+
node_id: this.nodeId ?? "",
|
|
4359
|
+
call_id: this.id,
|
|
4360
|
+
member_id: this.vertoManager.selfId ?? ""
|
|
4361
|
+
};
|
|
4362
|
+
if (typeof target === "object") return {
|
|
4363
|
+
...args,
|
|
4364
|
+
self,
|
|
4365
|
+
targets: [target]
|
|
4216
4366
|
};
|
|
4217
4367
|
return {
|
|
4218
4368
|
...args,
|
|
4219
|
-
self
|
|
4220
|
-
...reference,
|
|
4221
|
-
member_id: this.vertoManager.selfId
|
|
4222
|
-
},
|
|
4369
|
+
self,
|
|
4223
4370
|
target: {
|
|
4224
|
-
|
|
4371
|
+
node_id: this.nodeId ?? "",
|
|
4372
|
+
call_id: this.id,
|
|
4225
4373
|
member_id: target
|
|
4226
4374
|
}
|
|
4227
4375
|
};
|
|
4228
4376
|
}
|
|
4229
4377
|
/** Observable of the current call status (e.g. `'ringing'`, `'connected'`). */
|
|
4230
4378
|
get status$() {
|
|
4231
|
-
return this.cachedObservable("status$", () => (0, rxjs.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$))
|
|
4379
|
+
return this.cachedObservable("status$", () => (0, rxjs.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$).pipe((0, rxjs.distinctUntilChanged)(), (0, rxjs.tap)((status) => {
|
|
4380
|
+
this._lastMergedStatus = status;
|
|
4381
|
+
})));
|
|
4232
4382
|
}
|
|
4233
4383
|
/** Observable of the participants list, emits on join/leave/update. */
|
|
4234
4384
|
get participants$() {
|
|
@@ -4268,7 +4418,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4268
4418
|
}
|
|
4269
4419
|
/** Current call status. */
|
|
4270
4420
|
get status() {
|
|
4271
|
-
return this.
|
|
4421
|
+
return this._lastMergedStatus;
|
|
4272
4422
|
}
|
|
4273
4423
|
/** Whether the call is currently being recorded. */
|
|
4274
4424
|
get recording() {
|
|
@@ -4445,10 +4595,15 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4445
4595
|
async sendDigits(dtmf) {
|
|
4446
4596
|
return this.vertoManager.sendDigits(dtmf);
|
|
4447
4597
|
}
|
|
4448
|
-
/** Accepts an inbound call. */
|
|
4449
|
-
answer() {
|
|
4598
|
+
/** Accepts an inbound call, optionally overriding media options for the answer. */
|
|
4599
|
+
answer(options) {
|
|
4600
|
+
this._answerMediaOptions = options;
|
|
4450
4601
|
this._answered$.next(true);
|
|
4451
4602
|
}
|
|
4603
|
+
/** Media options provided when answering. Used internally by the VertoManager. */
|
|
4604
|
+
get answerMediaOptions() {
|
|
4605
|
+
return this._answerMediaOptions;
|
|
4606
|
+
}
|
|
4452
4607
|
/** Rejects an inbound call. */
|
|
4453
4608
|
reject() {
|
|
4454
4609
|
this._answered$.next(false);
|
|
@@ -4476,10 +4631,10 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4476
4631
|
}
|
|
4477
4632
|
/** Destroys the call, releasing all resources and subscriptions. */
|
|
4478
4633
|
destroy() {
|
|
4634
|
+
if (this._status$.value === "destroyed") return;
|
|
4479
4635
|
this._status$.next("destroyed");
|
|
4480
4636
|
this.vertoManager.destroy();
|
|
4481
4637
|
this.callEventsManager.destroy();
|
|
4482
|
-
this.participantsMap.clear();
|
|
4483
4638
|
super.destroy();
|
|
4484
4639
|
}
|
|
4485
4640
|
};
|
|
@@ -4487,6 +4642,23 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4487
4642
|
//#endregion
|
|
4488
4643
|
//#region src/managers/CallFactory.ts
|
|
4489
4644
|
/**
|
|
4645
|
+
* Infers the semantic error category from a raw Error thrown by VertoManager
|
|
4646
|
+
* or an RTCPeerConnection layer.
|
|
4647
|
+
*/
|
|
4648
|
+
function inferCallErrorKind(error) {
|
|
4649
|
+
if (error instanceof require_operators.RPCTimeoutError) return "timeout";
|
|
4650
|
+
if (error instanceof require_operators.JSONRPCError) return "signaling";
|
|
4651
|
+
if (error instanceof require_operators.MediaTrackError) return "media";
|
|
4652
|
+
if (error instanceof require_operators.WebSocketConnectionError || error instanceof require_operators.TransportConnectionError) return "network";
|
|
4653
|
+
return "internal";
|
|
4654
|
+
}
|
|
4655
|
+
/** Determines whether an error should be fatal (destroy the call). */
|
|
4656
|
+
function isFatalError(error) {
|
|
4657
|
+
if (error instanceof require_operators.VertoPongError) return false;
|
|
4658
|
+
if (error instanceof require_operators.MediaTrackError) return false;
|
|
4659
|
+
return true;
|
|
4660
|
+
}
|
|
4661
|
+
/**
|
|
4490
4662
|
* Factory for creating WebRTCCall instances with proper manager wiring.
|
|
4491
4663
|
* Eliminates circular dependencies by centralizing Call and Manager creation.
|
|
4492
4664
|
*/
|
|
@@ -4507,7 +4679,13 @@ var CallFactory = class {
|
|
|
4507
4679
|
vertoManager: new WebRTCVertoManager(callInstance, this.attachManager, this.deviceController, this.webRTCApiProvider, {
|
|
4508
4680
|
nodeId: options.nodeId,
|
|
4509
4681
|
onError: (error) => {
|
|
4510
|
-
|
|
4682
|
+
const callError = {
|
|
4683
|
+
kind: inferCallErrorKind(error),
|
|
4684
|
+
fatal: isFatalError(error),
|
|
4685
|
+
error,
|
|
4686
|
+
callId: callInstance.id
|
|
4687
|
+
};
|
|
4688
|
+
callInstance.emitError(callError);
|
|
4511
4689
|
}
|
|
4512
4690
|
}),
|
|
4513
4691
|
callEventsManager: new CallEventsManager(callInstance)
|
|
@@ -4884,9 +5062,15 @@ var PendingRPC = class PendingRPC {
|
|
|
4884
5062
|
return () => signal.removeEventListener("abort", abortHandler);
|
|
4885
5063
|
}) : rxjs.NEVER).subscribe({
|
|
4886
5064
|
next: (response) => {
|
|
4887
|
-
logger$7.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
|
|
4888
5065
|
isSettled = true;
|
|
4889
|
-
|
|
5066
|
+
if (response.error) {
|
|
5067
|
+
const rpcError = new require_operators.RPCError(response.error.code, request.id, response.error.message, response.error.data);
|
|
5068
|
+
logger$7.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with RPC error:`, rpcError);
|
|
5069
|
+
reject(rpcError);
|
|
5070
|
+
} else {
|
|
5071
|
+
logger$7.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
|
|
5072
|
+
resolve(response);
|
|
5073
|
+
}
|
|
4890
5074
|
subscription.unsubscribe();
|
|
4891
5075
|
},
|
|
4892
5076
|
error: (error) => {
|
|
@@ -4942,7 +5126,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
4942
5126
|
revision: 0
|
|
4943
5127
|
};
|
|
4944
5128
|
this._authorization$ = this.createBehaviorSubject(void 0);
|
|
4945
|
-
this._errors$ = this.
|
|
5129
|
+
this._errors$ = this.createReplaySubject(1);
|
|
4946
5130
|
this._authenticated$ = this.createBehaviorSubject(false);
|
|
4947
5131
|
this._subscriberInfo$ = this.createBehaviorSubject(null);
|
|
4948
5132
|
this._calls$ = this.createBehaviorSubject({});
|
|
@@ -5212,12 +5396,13 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5212
5396
|
}
|
|
5213
5397
|
async createOutboundCall(destination, options = {}) {
|
|
5214
5398
|
const destinationURI = destination instanceof Address ? destination.defaultChannel : destination;
|
|
5399
|
+
let callSession;
|
|
5215
5400
|
try {
|
|
5216
|
-
|
|
5401
|
+
callSession = await this.createCall({
|
|
5217
5402
|
to: destinationURI,
|
|
5218
5403
|
...options
|
|
5219
5404
|
});
|
|
5220
|
-
await (0, rxjs.firstValueFrom)(callSession.selfId$.pipe((0, rxjs.filter)((id) => Boolean(id)), (0, rxjs.take)(1), (0, rxjs.timeout)(this.callCreateTimeout)));
|
|
5405
|
+
await (0, rxjs.firstValueFrom)((0, rxjs.race)(callSession.selfId$.pipe((0, rxjs.filter)((id) => Boolean(id)), (0, rxjs.take)(1), (0, rxjs.timeout)(this.callCreateTimeout)), callSession.errors$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)((callError) => (0, rxjs.throwError)(() => callError.error)))));
|
|
5221
5406
|
this._calls$.next({
|
|
5222
5407
|
[`${callSession.id}`]: callSession,
|
|
5223
5408
|
...this._calls$.value
|
|
@@ -5225,7 +5410,8 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5225
5410
|
return callSession;
|
|
5226
5411
|
} catch (error) {
|
|
5227
5412
|
logger$6.error("[Session] Error creating outbound call:", error);
|
|
5228
|
-
|
|
5413
|
+
callSession?.destroy();
|
|
5414
|
+
const callError = new require_operators.CallCreateError(error instanceof rxjs.TimeoutError ? "Call create timeout" : "Call creation failed", error, "outbound");
|
|
5229
5415
|
this._errors$.next(callError);
|
|
5230
5416
|
throw callError;
|
|
5231
5417
|
}
|
|
@@ -5251,7 +5437,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5251
5437
|
return callSession;
|
|
5252
5438
|
} catch (error) {
|
|
5253
5439
|
logger$6.error("[Session] Error creating call session:", error);
|
|
5254
|
-
throw new require_operators.CallCreateError("Call create error", error);
|
|
5440
|
+
throw new require_operators.CallCreateError("Call create error", error, options.initOffer ? "inbound" : "outbound");
|
|
5255
5441
|
}
|
|
5256
5442
|
}
|
|
5257
5443
|
destroy() {
|
|
@@ -5497,7 +5683,7 @@ var WebSocketController = class WebSocketController extends Destroyable {
|
|
|
5497
5683
|
this.shouldReconnect = false;
|
|
5498
5684
|
this._status$ = this.createBehaviorSubject("disconnected");
|
|
5499
5685
|
this._incomingMessages$ = this.createSubject();
|
|
5500
|
-
this._errors$ = this.
|
|
5686
|
+
this._errors$ = this.createReplaySubject(1);
|
|
5501
5687
|
this.reconnectDelayMin = options.reconnectDelayMin ?? WebSocketController.DEFAULT_RECONNECT_DELAY_MIN_MS;
|
|
5502
5688
|
this.reconnectDelayMax = options.reconnectDelayMax ?? WebSocketController.DEFAULT_RECONNECT_DELAY_MAX_MS;
|
|
5503
5689
|
this.connectionTimeout = options.connectionTimeout ?? WebSocketController.DEFAULT_CONNECTION_TIMEOUT_MS;
|
|
@@ -5822,7 +6008,8 @@ const buildOptionsFromDestination = (destination) => {
|
|
|
5822
6008
|
const channel = new URLSearchParams(queryString).get("channel");
|
|
5823
6009
|
if (channel === "video") return {
|
|
5824
6010
|
audio: true,
|
|
5825
|
-
video: true
|
|
6011
|
+
video: true,
|
|
6012
|
+
receiveVideo: true
|
|
5826
6013
|
};
|
|
5827
6014
|
else if (channel === "audio") return {
|
|
5828
6015
|
audio: true,
|
|
@@ -5852,7 +6039,7 @@ var SignalWire = class extends Destroyable {
|
|
|
5852
6039
|
this._directory$ = this.createBehaviorSubject(void 0);
|
|
5853
6040
|
this._isConnected$ = this.createBehaviorSubject(false);
|
|
5854
6041
|
this._isRegistered$ = this.createBehaviorSubject(false);
|
|
5855
|
-
this._errors$ = this.
|
|
6042
|
+
this._errors$ = this.createReplaySubject(1);
|
|
5856
6043
|
this._options = {};
|
|
5857
6044
|
this._deps = new DependencyContainer();
|
|
5858
6045
|
this._options = {
|
|
@@ -5929,7 +6116,12 @@ var SignalWire = class extends Destroyable {
|
|
|
5929
6116
|
this._subscriber$.next(new Subscriber(this._deps.http));
|
|
5930
6117
|
if (!this._options.skipConnection) await this.connect();
|
|
5931
6118
|
if (!this._options.reconnectAttachedCalls && this._attachManager) await this._attachManager.flush();
|
|
5932
|
-
if (!this._options.skipRegister)
|
|
6119
|
+
if (!this._options.skipRegister) try {
|
|
6120
|
+
await this.register();
|
|
6121
|
+
} catch (error) {
|
|
6122
|
+
logger$1.error("[SignalWire] Registration failed:", error);
|
|
6123
|
+
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
6124
|
+
}
|
|
5933
6125
|
this.handleAttachments();
|
|
5934
6126
|
}
|
|
5935
6127
|
async handleAttachments() {
|
|
@@ -6092,8 +6284,22 @@ var SignalWire = class extends Destroyable {
|
|
|
6092
6284
|
}));
|
|
6093
6285
|
this._isRegistered$.next(true);
|
|
6094
6286
|
} catch (error) {
|
|
6095
|
-
logger$1.
|
|
6287
|
+
logger$1.debug("[SignalWire] Failed to register subscriber, trying reauthentication...");
|
|
6288
|
+
if (this._deps.credential.token) this._clientSession.reauthenticate(this._deps.credential.token).then(async () => {
|
|
6289
|
+
logger$1.debug("[SignalWire] Reauthentication successful, retrying register()");
|
|
6290
|
+
await this._transport.execute(RPCExecute({
|
|
6291
|
+
method: "subscriber.online",
|
|
6292
|
+
params: {}
|
|
6293
|
+
}));
|
|
6294
|
+
this._isRegistered$.next(true);
|
|
6295
|
+
}).catch((reauthError) => {
|
|
6296
|
+
logger$1.error("[SignalWire] Reauthentication failed during register():", reauthError);
|
|
6297
|
+
const registerError = new require_operators.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 }) });
|
|
6298
|
+
this._errors$.next(registerError);
|
|
6299
|
+
throw registerError;
|
|
6300
|
+
});
|
|
6096
6301
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
6302
|
+
throw error;
|
|
6097
6303
|
}
|
|
6098
6304
|
}
|
|
6099
6305
|
/** Unregisters the subscriber, going offline for inbound calls. */
|