@wazo/sdk 1.0.0-alpha.2 → 1.0.0-alpha.3
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/wazo-sdk.js +2 -2
- package/esm/__tests__/__voice__/call.test.js +1 -0
- package/esm/domain/Phone/CTIPhone.js +2 -2
- package/esm/index.js +1 -1
- package/esm/service/CallApi.js +4 -4
- package/esm/types/domain/Phone/CTIPhone.d.ts.map +1 -1
- package/esm/types/index.d.ts +1 -1
- package/esm/types/index.d.ts.map +1 -1
- package/esm/types/service/CallApi.d.ts +5 -5
- package/esm/types/service/CallApi.d.ts.map +1 -1
- package/esm/types/state-machine/softphone-state-machine.d.ts +1 -1
- package/esm/types/voice/call.d.ts +9 -2
- package/esm/types/voice/call.d.ts.map +1 -1
- package/esm/types/voice/softphone.d.ts +4 -0
- package/esm/types/voice/softphone.d.ts.map +1 -1
- package/esm/voice/call.js +28 -6
- package/esm/voice/softphone.js +11 -2
- package/lib/__tests__/__voice__/call.test.js +1 -0
- package/lib/domain/Phone/CTIPhone.js +2 -2
- package/lib/index.js +2 -2
- package/lib/service/CallApi.js +2 -2
- package/lib/types/domain/Phone/CTIPhone.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/service/CallApi.d.ts +5 -5
- package/lib/types/service/CallApi.d.ts.map +1 -1
- package/lib/types/state-machine/softphone-state-machine.d.ts +1 -1
- package/lib/types/voice/call.d.ts +9 -2
- package/lib/types/voice/call.d.ts.map +1 -1
- package/lib/types/voice/softphone.d.ts +4 -0
- package/lib/types/voice/softphone.d.ts.map +1 -1
- package/lib/voice/call.js +29 -7
- package/lib/voice/softphone.js +14 -2
- package/package.json +1 -1
- package/src/__tests__/__voice__/call.test.ts +1 -0
- package/src/domain/Phone/CTIPhone.ts +3 -2
- package/src/index.ts +1 -1
- package/src/service/CallApi.ts +7 -7
- package/src/voice/call.ts +36 -8
- package/src/voice/softphone.ts +15 -2
|
@@ -30,6 +30,7 @@ export type CallOptions = {
|
|
|
30
30
|
withCamera?: boolean;
|
|
31
31
|
audioOnly?: boolean;
|
|
32
32
|
conference?: boolean;
|
|
33
|
+
extraHeaders?: Record<string, any>;
|
|
33
34
|
};
|
|
34
35
|
export declare class Softphone extends EventEmitter {
|
|
35
36
|
audioOutputDeviceId?: string;
|
|
@@ -46,6 +47,7 @@ export declare class Softphone extends EventEmitter {
|
|
|
46
47
|
ringingEnabled: boolean;
|
|
47
48
|
constructor();
|
|
48
49
|
connect(options?: Partial<WebRtcConfig>): Promise<void>;
|
|
50
|
+
hangupAllCalls(): Promise<boolean[]>;
|
|
49
51
|
disconnect(): Promise<void | null>;
|
|
50
52
|
getPrimaryWebRtcLine(): SipLine | null;
|
|
51
53
|
connectWithCredentials(server: string, sipLine: SipLine, displayName: string, rawOptions?: Partial<WebRtcConfig>): Promise<void>;
|
|
@@ -67,8 +69,10 @@ export declare class Softphone extends EventEmitter {
|
|
|
67
69
|
changeAudioVolume(volume: number): void;
|
|
68
70
|
changeRingVolume(volume: number): void;
|
|
69
71
|
getCurrentCall(): Call | undefined;
|
|
72
|
+
getActiveCalls(): Call[];
|
|
70
73
|
getIncomingCalls(): Call[];
|
|
71
74
|
get state(): StateTypes;
|
|
75
|
+
get user(): string | undefined;
|
|
72
76
|
getUserAgent(): string;
|
|
73
77
|
isRegistered(): boolean;
|
|
74
78
|
_bindEvents(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"softphone.d.ts","sourceRoot":"","sources":["../../../src/voice/softphone.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAKtC,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAI7C,OAA8B,EAAE,KAAK,iBAAiB,EAAW,KAAK,UAAU,EAAuB,MAAM,0CAA0C,CAAC;AACxJ,OAAO,EAAE,YAAY,EAAW,MAAM,iBAAiB,CAAC;AACxD,OAAO,gBAAgB,MAAM,mBAAmB,CAAC;AAGjD,OAAO,IAAI,MAAM,QAAQ,CAAC;AAG1B,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAC1D,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,wBAAwB,qBAAqB,CAAC;AAC3D,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AACtD,eAAO,MAAM,uBAAuB,oBAAoB,CAAC;AACzD,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AACrD,eAAO,MAAM,6BAA6B,yBAAyB,CAAC;AACpE,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAC7C,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"softphone.d.ts","sourceRoot":"","sources":["../../../src/voice/softphone.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAKtC,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAI7C,OAA8B,EAAE,KAAK,iBAAiB,EAAW,KAAK,UAAU,EAAuB,MAAM,0CAA0C,CAAC;AACxJ,OAAO,EAAE,YAAY,EAAW,MAAM,iBAAiB,CAAC;AACxD,OAAO,gBAAgB,MAAM,mBAAmB,CAAC;AAGjD,OAAO,IAAI,MAAM,QAAQ,CAAC;AAG1B,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAC1D,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,wBAAwB,qBAAqB,CAAC;AAC3D,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AACtD,eAAO,MAAM,uBAAuB,oBAAoB,CAAC;AACzD,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AACrD,eAAO,MAAM,6BAA6B,yBAAyB,CAAC;AACpE,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAC7C,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACpC,CAAC;AAIF,qBAAa,SAAU,SAAQ,YAAY;IACzC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,iBAAiB,EAAE,MAAM,CAAC;IAE1B,eAAe,EAAE,MAAM,CAAC;IAExB,KAAK,EAAE,IAAI,EAAE,CAAC;IAEd,MAAM,EAAE,gBAAgB,CAAC;IAEzB,OAAO,EAAE,OAAO,CAAC;IAEjB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAExB,cAAc,EAAE,iBAAiB,CAAC;IAElC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAE/B,kBAAkB,EAAE,OAAO,CAAC;IAE5B,cAAc,UAAQ;;IAWtB,OAAO,CAAC,OAAO,GAAE,OAAO,CAAC,YAAY,CAAM;IAyBrC,cAAc;IAId,UAAU;IAYhB,oBAAoB,IAAI,OAAO,GAAG,IAAI;IAIhC,sBAAsB,CAC1B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,MAAM,EACnB,UAAU,GAAE,OAAO,CAAC,YAAY,CAAM,GACrC,OAAO,CAAC,IAAI,CAAC;IAqChB,SAAS;IASH,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAqCtD,UAAU,CAAC,YAAY,EAAE,IAAI;IAI7B,gBAAgB,CAAC,IAAI,EAAE,IAAI;IAqD3B,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAKrC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAKtC,YAAY,CAAC,UAAU,GAAE,IAAI,GAAG,IAAW;IAI3C,cAAc;IASd,aAAa;IASb,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI;IAIxD,uBAAuB,CAAC,EAAE,EAAE,MAAM;IAOlC,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;IAOlD,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IAOlF,gBAAgB,CAAC,EAAE,EAAE,MAAM;IAK3B,MAAM,IAAI,OAAO;IAKjB,iBAAiB,CAAC,MAAM,EAAE,MAAM;IAOhC,gBAAgB,CAAC,MAAM,EAAE,MAAM;IAK/B,cAAc,IAAI,IAAI,GAAG,SAAS;IAIlC,cAAc,IAAI,IAAI,EAAE;IAIxB,gBAAgB,IAAI,IAAI,EAAE;IAI1B,IAAI,KAAK,IAAI,UAAU,CAEtB;IAED,IAAI,IAAI,uBAEP;IAED,YAAY;IAIZ,YAAY;IAIZ,WAAW,IAAI,IAAI;IAiJnB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,UAAU;CAiCnB;;AAED,wBAA+B"}
|
package/lib/voice/call.js
CHANGED
|
@@ -35,13 +35,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.MESSAGE_TRACK_UPDATED = exports.MESSAGE_TYPE_SIGNAL = exports.MESSAGE_TYPE_CHAT = exports.EVENT_CAMERA_DISABLED = exports.EVENT_CAMERA_RESUMED = exports.EVENT_WEB_RTC_STATS = exports.EVENT_SHARE_SCREEN_ENDED = exports.EVENT_SHARE_SCREEN_STARTED = exports.EVENT_SHARE_SCREEN_ENDING = exports.EVENT_REMOVE_STREAM = exports.EVENT_VIDEO_STREAM = exports.EVENT_AUDIO_STREAM = exports.EVENT_TRACK = exports.EVENT_REINVITE = exports.EVENT_CALL_RESUMED = exports.EVENT_CALL_HELD = exports.EVENT_CALL_UN_MUTED = exports.EVENT_CALL_MUTED = exports.EVENT_CALL_ENDED = exports.EVENT_CALL_TERMINATING = exports.EVENT_CALL_REJECTED = exports.EVENT_CALL_ERROR = exports.EVENT_EARLY_MEDIA = exports.EVENT_PROGRESS = exports.EVENT_CALL_CANCELED = exports.
|
|
38
|
+
exports.MESSAGE_TRACK_UPDATED = exports.MESSAGE_TYPE_SIGNAL = exports.MESSAGE_TYPE_CHAT = exports.EVENT_CAMERA_DISABLED = exports.EVENT_CAMERA_RESUMED = exports.EVENT_WEB_RTC_STATS = exports.EVENT_SHARE_SCREEN_ENDED = exports.EVENT_SHARE_SCREEN_STARTED = exports.EVENT_SHARE_SCREEN_ENDING = exports.EVENT_REMOVE_STREAM = exports.EVENT_VIDEO_STREAM = exports.EVENT_AUDIO_STREAM = exports.EVENT_TRACK = exports.EVENT_REINVITE = exports.EVENT_CALL_RESUMED = exports.EVENT_CALL_HELD = exports.EVENT_CALL_UN_MUTED = exports.EVENT_CALL_MUTED = exports.EVENT_CALL_ENDED = exports.EVENT_CALL_TERMINATING = exports.EVENT_CALL_REJECTED = exports.EVENT_CALL_ERROR = exports.EVENT_EARLY_MEDIA = exports.EVENT_PROGRESS = exports.EVENT_CALL_CANCELED = exports.EVENT_CALL_LOCALLY_ACCEPTED = exports.EVENT_CALL_REMOTLY_ACCEPTED = void 0;
|
|
39
39
|
/* eslint-disable no-underscore-dangle */
|
|
40
40
|
const events_1 = require("events");
|
|
41
41
|
const xstate_1 = require("xstate");
|
|
42
42
|
const invitation_1 = require("sip.js/lib/api/invitation");
|
|
43
43
|
const session_state_1 = require("sip.js/lib/api/session-state");
|
|
44
44
|
const call_state_machine_1 = __importStar(require("../state-machine/call-state-machine"));
|
|
45
|
+
const new_from_1 = __importDefault(require("../utils/new-from"));
|
|
46
|
+
const update_from_1 = __importDefault(require("../utils/update-from"));
|
|
45
47
|
const IssueReporter_1 = __importDefault(require("../service/IssueReporter"));
|
|
46
48
|
const softphone_1 = __importStar(require("./softphone"));
|
|
47
49
|
const sdp_1 = require("../utils/sdp");
|
|
@@ -49,7 +51,8 @@ const utils_1 = require("../state-machine/utils");
|
|
|
49
51
|
const webrtc_1 = require("../utils/webrtc");
|
|
50
52
|
const logger = IssueReporter_1.default.loggerFor('call');
|
|
51
53
|
// Events
|
|
52
|
-
exports.
|
|
54
|
+
exports.EVENT_CALL_REMOTLY_ACCEPTED = 'remotelyAccepted';
|
|
55
|
+
exports.EVENT_CALL_LOCALLY_ACCEPTED = 'locallyAccepted';
|
|
53
56
|
exports.EVENT_CALL_CANCELED = 'canceled';
|
|
54
57
|
exports.EVENT_PROGRESS = 'progress';
|
|
55
58
|
exports.EVENT_EARLY_MEDIA = 'earlyMedia';
|
|
@@ -76,6 +79,9 @@ exports.MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
|
|
|
76
79
|
exports.MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
|
|
77
80
|
exports.MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
|
|
78
81
|
class Call extends events_1.EventEmitter {
|
|
82
|
+
static newFrom(call) {
|
|
83
|
+
return (0, new_from_1.default)(call, Call);
|
|
84
|
+
}
|
|
79
85
|
static parseCall(apiCall) {
|
|
80
86
|
const sipCall = {
|
|
81
87
|
id: apiCall.sipCallId,
|
|
@@ -141,6 +147,7 @@ class Call extends events_1.EventEmitter {
|
|
|
141
147
|
this.answerTime = new Date();
|
|
142
148
|
return this.phone.client.answer(this.sipCall, options.withCamera).then(() => {
|
|
143
149
|
logger.info('call - accepted', Object.assign({ id: this.id }, options));
|
|
150
|
+
this.emit(exports.EVENT_CALL_LOCALLY_ACCEPTED, this);
|
|
144
151
|
return this.id;
|
|
145
152
|
}).catch(e => {
|
|
146
153
|
logger.error(e);
|
|
@@ -279,9 +286,21 @@ class Call extends events_1.EventEmitter {
|
|
|
279
286
|
isHeld() {
|
|
280
287
|
return this._hasEstablishedState(call_state_machine_1.EstablishedStates.HELD);
|
|
281
288
|
}
|
|
289
|
+
isEstablishing() {
|
|
290
|
+
return this.sipCall.state === session_state_1.SessionState.Establishing;
|
|
291
|
+
}
|
|
282
292
|
isEstablished() {
|
|
283
293
|
return call_state_machine_1.States.ESTABLISHED in this.state;
|
|
284
294
|
}
|
|
295
|
+
isRinging() {
|
|
296
|
+
return this.state === call_state_machine_1.States.RINGING;
|
|
297
|
+
}
|
|
298
|
+
isOutgoing() {
|
|
299
|
+
return this.sipCall instanceof invitation_1.Invitation;
|
|
300
|
+
}
|
|
301
|
+
isIncoming() {
|
|
302
|
+
return !this.isOutgoing();
|
|
303
|
+
}
|
|
285
304
|
isConference() {
|
|
286
305
|
var _a;
|
|
287
306
|
return (_a = (0, webrtc_1.getPeerConnection)(this.sipCall)) === null || _a === void 0 ? void 0 : _a.sfu;
|
|
@@ -289,7 +308,7 @@ class Call extends events_1.EventEmitter {
|
|
|
289
308
|
transfer(target) {
|
|
290
309
|
(0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
|
|
291
310
|
logger.info('call - transfer', { id: this.id, target });
|
|
292
|
-
this.phone.client.transfer(this.sipCall, target);
|
|
311
|
+
return this.phone.client.transfer(this.sipCall, target);
|
|
293
312
|
}
|
|
294
313
|
atxfer() {
|
|
295
314
|
(0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
|
|
@@ -429,7 +448,7 @@ class Call extends events_1.EventEmitter {
|
|
|
429
448
|
}
|
|
430
449
|
onAccepted() {
|
|
431
450
|
this._sendAction(call_state_machine_1.Actions.REMOTLY_ACCEPTED);
|
|
432
|
-
this.emit(exports.
|
|
451
|
+
this.emit(exports.EVENT_CALL_REMOTLY_ACCEPTED);
|
|
433
452
|
}
|
|
434
453
|
onProgress() {
|
|
435
454
|
this.emit(exports.EVENT_PROGRESS);
|
|
@@ -478,12 +497,15 @@ class Call extends events_1.EventEmitter {
|
|
|
478
497
|
isVideoRemotelyHeld() {
|
|
479
498
|
return (0, webrtc_1.isVideoRemotelyHeld)(this.sipCall);
|
|
480
499
|
}
|
|
481
|
-
isRinging() {
|
|
482
|
-
return this.state === call_state_machine_1.States.RINGING;
|
|
483
|
-
}
|
|
484
500
|
onReinvite(request, updatedCalleeName, updatedNumber, hadRemoteVideo) {
|
|
485
501
|
this.emit(exports.EVENT_REINVITE, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
|
|
486
502
|
}
|
|
503
|
+
updateFrom(call) {
|
|
504
|
+
(0, update_from_1.default)(this, call);
|
|
505
|
+
}
|
|
506
|
+
is(otherCall) {
|
|
507
|
+
return otherCall && this.id && this.id === otherCall.id;
|
|
508
|
+
}
|
|
487
509
|
get id() {
|
|
488
510
|
return (0, sdp_1.getSipSessionId)(this.sipCall);
|
|
489
511
|
}
|
package/lib/voice/softphone.js
CHANGED
|
@@ -91,6 +91,11 @@ class Softphone extends events_1.EventEmitter {
|
|
|
91
91
|
this.options.userUuid = session.uuid || '';
|
|
92
92
|
return this.connectWithCredentials(server, this.sipLine, session.displayName(), options);
|
|
93
93
|
}
|
|
94
|
+
hangupAllCalls() {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
return Promise.all(this.calls.map(call => call.hangup()));
|
|
97
|
+
});
|
|
98
|
+
}
|
|
94
99
|
disconnect() {
|
|
95
100
|
return __awaiter(this, void 0, void 0, function* () {
|
|
96
101
|
(0, utils_1.assertCan)(this.softphoneActor, softphone_state_machine_1.Actions.UNREGISTER);
|
|
@@ -98,7 +103,7 @@ class Softphone extends events_1.EventEmitter {
|
|
|
98
103
|
return null;
|
|
99
104
|
}
|
|
100
105
|
// Terminate all calls
|
|
101
|
-
yield
|
|
106
|
+
yield this.hangupAllCalls();
|
|
102
107
|
return this.client.unregister();
|
|
103
108
|
});
|
|
104
109
|
}
|
|
@@ -275,7 +280,10 @@ class Softphone extends events_1.EventEmitter {
|
|
|
275
280
|
this.audioRingVolume = volume;
|
|
276
281
|
}
|
|
277
282
|
getCurrentCall() {
|
|
278
|
-
return this.
|
|
283
|
+
return this.getActiveCalls()[0];
|
|
284
|
+
}
|
|
285
|
+
getActiveCalls() {
|
|
286
|
+
return this.calls.filter(call => call.isEstablished());
|
|
279
287
|
}
|
|
280
288
|
getIncomingCalls() {
|
|
281
289
|
return this.calls.filter(call => call.isRinging());
|
|
@@ -283,6 +291,10 @@ class Softphone extends events_1.EventEmitter {
|
|
|
283
291
|
get state() {
|
|
284
292
|
return (0, utils_1.getState)(this.softphoneActor);
|
|
285
293
|
}
|
|
294
|
+
get user() {
|
|
295
|
+
var _a, _b, _c, _d;
|
|
296
|
+
return (_d = (_c = (_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.userAgent) === null || _b === void 0 ? void 0 : _b.contact) === null || _c === void 0 ? void 0 : _c.uri) === null || _d === void 0 ? void 0 : _d.user;
|
|
297
|
+
}
|
|
286
298
|
getUserAgent() {
|
|
287
299
|
var _a, _b;
|
|
288
300
|
return ((_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b.userAgentString) || 'softphone';
|
package/package.json
CHANGED
|
@@ -79,6 +79,7 @@ describe('Call', () => {
|
|
|
79
79
|
expect(call.answerTime).toStrictEqual(apiCall.startingTime);
|
|
80
80
|
expect(call.isMuted()).toBeTruthy();
|
|
81
81
|
expect(call.state).toStrictEqual({ [States.ESTABLISHED]: EstablishedStates.MUTED });
|
|
82
|
+
expect(call.isEstablished()).toBeTruthy();
|
|
82
83
|
});
|
|
83
84
|
});
|
|
84
85
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Session from '../Session';
|
|
2
2
|
import Call from '../Call';
|
|
3
|
+
import SoftphoneCall from '../../voice/call';
|
|
3
4
|
import Line from '../Line';
|
|
4
5
|
import CallSession from '../CallSession';
|
|
5
6
|
import type { Phone, AvailablePhoneOptions } from './Phone';
|
|
@@ -141,7 +142,7 @@ export default class CTIPhone extends Emitter implements Phone {
|
|
|
141
142
|
});
|
|
142
143
|
|
|
143
144
|
try {
|
|
144
|
-
await CallApi.cancelCall(callSession);
|
|
145
|
+
await CallApi.cancelCall({ apiId: callSession.getId() } as SoftphoneCall);
|
|
145
146
|
|
|
146
147
|
if (this.currentCall && callSession.callId === this.currentCall.id) {
|
|
147
148
|
this.endCurrentCall(callSession);
|
|
@@ -167,7 +168,7 @@ export default class CTIPhone extends Emitter implements Phone {
|
|
|
167
168
|
callId: callSession.getId(),
|
|
168
169
|
number: callSession.number,
|
|
169
170
|
});
|
|
170
|
-
await CallApi.cancelCall(callSession);
|
|
171
|
+
await CallApi.cancelCall({ id: callSession.getId() } as SoftphoneCall);
|
|
171
172
|
this.eventEmitter.emit('onCallEnded', callSession);
|
|
172
173
|
}
|
|
173
174
|
|
package/src/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { default as ServerError } from './domain/ServerError';
|
|
|
7
7
|
export { default as InvalidStateTransition } from './domain/InvalidStateTransition';
|
|
8
8
|
export { default as InvalidState } from './domain/InvalidState';
|
|
9
9
|
export { default as SFUNotAvailableError } from './domain/SFUNotAvailableError';
|
|
10
|
-
export { default as
|
|
10
|
+
export { default as ApiCall } from './domain/Call';
|
|
11
11
|
export { default as CallLog } from './domain/CallLog';
|
|
12
12
|
export { default as Recording } from './domain/Recording';
|
|
13
13
|
export { default as ChatMessage } from './domain/ChatMessage';
|
package/src/service/CallApi.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import ApiCall from '../domain/Call';
|
|
2
|
+
import Call from '../voice/call';
|
|
2
3
|
import CallLog from '../domain/CallLog';
|
|
3
4
|
import Line from '../domain/Line';
|
|
4
5
|
import Session from '../domain/Session';
|
|
5
6
|
import Relocation from '../domain/Relocation';
|
|
6
|
-
import CallSession from '../domain/CallSession';
|
|
7
7
|
import getApiClient from './getApiClient';
|
|
8
8
|
import Transfer from '../domain/IndirectTransfer';
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ export default class CallApi {
|
|
|
16
16
|
return getApiClient().callLogd.listDistinctCallLogs(offset, limit, distinct);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
static async fetchActiveCalls(): Promise<
|
|
19
|
+
static async fetchActiveCalls(): Promise<ApiCall[]> {
|
|
20
20
|
return getApiClient().calld.listCalls();
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -37,14 +37,14 @@ export default class CallApi {
|
|
|
37
37
|
return getApiClient().confd.getUserLineSip(session.uuid as string, lineToUse ? <unknown>lineToUse.id as string : '');
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
static async cancelCall(
|
|
41
|
-
return getApiClient().calld.cancelCall(
|
|
40
|
+
static async cancelCall(call: Call): Promise<boolean> {
|
|
41
|
+
return getApiClient().calld.cancelCall(call.apiId || '');
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
static async makeCall(callFromLine: Line, extension: string, isMobile = false, callbackAllLines = false): Promise<
|
|
44
|
+
static async makeCall(callFromLine: Line, extension: string, isMobile = false, callbackAllLines = false): Promise<ApiCall | null | undefined> {
|
|
45
45
|
const lineId = callFromLine ? callFromLine.id : null;
|
|
46
46
|
const response = await getApiClient().calld.makeCall(extension, isMobile, lineId, callbackAllLines);
|
|
47
|
-
return
|
|
47
|
+
return ApiCall.parse(response);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
static async relocateCall(callId: string, line: number, contactIdentifier?: string): Promise<Relocation> {
|
package/src/voice/call.ts
CHANGED
|
@@ -11,7 +11,8 @@ import type { IncomingRequestMessage } from 'sip.js/lib/core/messages/incoming-r
|
|
|
11
11
|
import callStateMachine, { type ActionTypes, Actions, type EstablishedActionTypes, EstablishedActions, States, type StateTypes, EstablishedStates, type EstablishedStateTypes, type CallActorRef } from '../state-machine/call-state-machine';
|
|
12
12
|
import { SipCall, PeerConnection } from '../domain/types';
|
|
13
13
|
import ApiCall from '../domain/Call';
|
|
14
|
-
|
|
14
|
+
import newFrom from '../utils/new-from';
|
|
15
|
+
import updateFrom from '../utils/update-from';
|
|
15
16
|
import IssueReporter from '../service/IssueReporter';
|
|
16
17
|
import softphone, { EVENT_TERMINATE_SOUND, Softphone } from './softphone';
|
|
17
18
|
import { getCallDisplayName, getCallNumber, getSipSessionId } from '../utils/sdp';
|
|
@@ -32,7 +33,8 @@ export type ReinviteOptions = {
|
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
// Events
|
|
35
|
-
export const
|
|
36
|
+
export const EVENT_CALL_REMOTLY_ACCEPTED = 'remotelyAccepted';
|
|
37
|
+
export const EVENT_CALL_LOCALLY_ACCEPTED = 'locallyAccepted';
|
|
36
38
|
export const EVENT_CALL_CANCELED = 'canceled';
|
|
37
39
|
export const EVENT_PROGRESS = 'progress';
|
|
38
40
|
export const EVENT_EARLY_MEDIA = 'earlyMedia';
|
|
@@ -88,6 +90,10 @@ class Call extends EventEmitter {
|
|
|
88
90
|
|
|
89
91
|
currentScreenShare: Record<string, any> | null;
|
|
90
92
|
|
|
93
|
+
static newFrom(call: Call) {
|
|
94
|
+
return newFrom(call, Call);
|
|
95
|
+
}
|
|
96
|
+
|
|
91
97
|
static parseCall(apiCall: ApiCall): Call {
|
|
92
98
|
const sipCall = {
|
|
93
99
|
id: apiCall.sipCallId,
|
|
@@ -170,6 +176,8 @@ class Call extends EventEmitter {
|
|
|
170
176
|
return this.phone.client.answer(this.sipCall as Invitation, options.withCamera).then(() => {
|
|
171
177
|
logger.info('call - accepted', { id: this.id, ...options });
|
|
172
178
|
|
|
179
|
+
this.emit(EVENT_CALL_LOCALLY_ACCEPTED, this);
|
|
180
|
+
|
|
173
181
|
return this.id;
|
|
174
182
|
}).catch(e => {
|
|
175
183
|
logger.error(e);
|
|
@@ -343,10 +351,26 @@ class Call extends EventEmitter {
|
|
|
343
351
|
return this._hasEstablishedState(EstablishedStates.HELD);
|
|
344
352
|
}
|
|
345
353
|
|
|
354
|
+
isEstablishing() {
|
|
355
|
+
return this.sipCall.state === SessionState.Establishing;
|
|
356
|
+
}
|
|
357
|
+
|
|
346
358
|
isEstablished() {
|
|
347
359
|
return States.ESTABLISHED in (this.state as Record<StateTypes, EstablishedStateTypes>);
|
|
348
360
|
}
|
|
349
361
|
|
|
362
|
+
isRinging() {
|
|
363
|
+
return this.state === States.RINGING;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
isOutgoing() {
|
|
367
|
+
return this.sipCall instanceof Invitation;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
isIncoming() {
|
|
371
|
+
return !this.isOutgoing();
|
|
372
|
+
}
|
|
373
|
+
|
|
350
374
|
isConference(): boolean {
|
|
351
375
|
return (getPeerConnection(this.sipCall) as PeerConnection)?.sfu;
|
|
352
376
|
}
|
|
@@ -355,7 +379,7 @@ class Call extends EventEmitter {
|
|
|
355
379
|
assertState(this.callActor, States.ESTABLISHED);
|
|
356
380
|
logger.info('call - transfer', { id: this.id, target });
|
|
357
381
|
|
|
358
|
-
this.phone.client.transfer(this.sipCall, target);
|
|
382
|
+
return this.phone.client.transfer(this.sipCall, target);
|
|
359
383
|
}
|
|
360
384
|
|
|
361
385
|
atxfer(): Record<string, any> | null | undefined {
|
|
@@ -528,7 +552,7 @@ class Call extends EventEmitter {
|
|
|
528
552
|
|
|
529
553
|
onAccepted() {
|
|
530
554
|
this._sendAction(Actions.REMOTLY_ACCEPTED);
|
|
531
|
-
this.emit(
|
|
555
|
+
this.emit(EVENT_CALL_REMOTLY_ACCEPTED);
|
|
532
556
|
}
|
|
533
557
|
|
|
534
558
|
onProgress() {
|
|
@@ -595,14 +619,18 @@ class Call extends EventEmitter {
|
|
|
595
619
|
return isVideoRemotelyHeld(this.sipCall);
|
|
596
620
|
}
|
|
597
621
|
|
|
598
|
-
isRinging() {
|
|
599
|
-
return this.state === States.RINGING;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
622
|
onReinvite(request: IncomingRequestMessage, updatedCalleeName: string, updatedNumber: string, hadRemoteVideo: boolean) {
|
|
603
623
|
this.emit(EVENT_REINVITE, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
|
|
604
624
|
}
|
|
605
625
|
|
|
626
|
+
updateFrom(call: Call) {
|
|
627
|
+
updateFrom(this, call);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
is(otherCall: Call) {
|
|
631
|
+
return otherCall && this.id && this.id === otherCall.id;
|
|
632
|
+
}
|
|
633
|
+
|
|
606
634
|
get id() {
|
|
607
635
|
return getSipSessionId(this.sipCall);
|
|
608
636
|
}
|
package/src/voice/softphone.ts
CHANGED
|
@@ -44,6 +44,7 @@ export type CallOptions = {
|
|
|
44
44
|
// If audioOnly is set to true, all video stream will be deactivated, even remotes ones.
|
|
45
45
|
audioOnly?: boolean,
|
|
46
46
|
conference?: boolean,
|
|
47
|
+
extraHeaders?: Record<string, any>,
|
|
47
48
|
};
|
|
48
49
|
|
|
49
50
|
const logger = IssueReporter.loggerFor('softphone');
|
|
@@ -107,6 +108,10 @@ export class Softphone extends EventEmitter {
|
|
|
107
108
|
return this.connectWithCredentials(server, this.sipLine, session.displayName(), options);
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
async hangupAllCalls() {
|
|
112
|
+
return Promise.all(this.calls.map(call => call.hangup()));
|
|
113
|
+
}
|
|
114
|
+
|
|
110
115
|
async disconnect() {
|
|
111
116
|
assertCan(this.softphoneActor, Actions.UNREGISTER);
|
|
112
117
|
if (!this.client) {
|
|
@@ -114,7 +119,7 @@ export class Softphone extends EventEmitter {
|
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
// Terminate all calls
|
|
117
|
-
await
|
|
122
|
+
await this.hangupAllCalls();
|
|
118
123
|
|
|
119
124
|
return this.client.unregister();
|
|
120
125
|
}
|
|
@@ -348,7 +353,11 @@ export class Softphone extends EventEmitter {
|
|
|
348
353
|
}
|
|
349
354
|
|
|
350
355
|
getCurrentCall(): Call | undefined {
|
|
351
|
-
return this.
|
|
356
|
+
return this.getActiveCalls()[0];
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
getActiveCalls(): Call[] {
|
|
360
|
+
return this.calls.filter(call => call.isEstablished());
|
|
352
361
|
}
|
|
353
362
|
|
|
354
363
|
getIncomingCalls(): Call[] {
|
|
@@ -359,6 +368,10 @@ export class Softphone extends EventEmitter {
|
|
|
359
368
|
return getState(this.softphoneActor) as StateTypes;
|
|
360
369
|
}
|
|
361
370
|
|
|
371
|
+
get user() {
|
|
372
|
+
return this.client?.userAgent?.contact?.uri?.user;
|
|
373
|
+
}
|
|
374
|
+
|
|
362
375
|
getUserAgent() {
|
|
363
376
|
return this.client?.config?.userAgentString || 'softphone';
|
|
364
377
|
}
|