@telnyx/react-voice-commons-sdk 0.1.2 → 0.1.4
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/CHANGELOG.md +60 -0
- package/README.md +469 -483
- package/ios/CallKitBridge.swift +2 -7
- package/lib/callkit/callkit-coordinator.d.ts +110 -117
- package/lib/callkit/callkit-coordinator.js +664 -727
- package/lib/callkit/callkit.d.ts +41 -41
- package/lib/callkit/callkit.js +252 -242
- package/lib/callkit/index.js +15 -47
- package/lib/callkit/use-callkit.d.ts +19 -19
- package/lib/callkit/use-callkit.js +270 -310
- package/lib/context/TelnyxVoiceContext.d.ts +9 -9
- package/lib/context/TelnyxVoiceContext.js +10 -13
- package/lib/hooks/use-callkit-coordinator.d.ts +9 -17
- package/lib/hooks/use-callkit-coordinator.js +45 -50
- package/lib/hooks/useAppReadyNotifier.js +13 -15
- package/lib/hooks/useAppStateHandler.d.ts +6 -11
- package/lib/hooks/useAppStateHandler.js +95 -110
- package/lib/hooks/useNetworkStateHandler.d.ts +0 -0
- package/lib/hooks/useNetworkStateHandler.js +0 -0
- package/lib/index.d.ts +3 -21
- package/lib/index.js +50 -201
- package/lib/internal/CallKitHandler.d.ts +6 -6
- package/lib/internal/CallKitHandler.js +96 -104
- package/lib/internal/callkit-manager.d.ts +57 -57
- package/lib/internal/callkit-manager.js +299 -316
- package/lib/internal/calls/call-state-controller.d.ts +73 -86
- package/lib/internal/calls/call-state-controller.js +263 -307
- package/lib/internal/session/session-manager.d.ts +71 -75
- package/lib/internal/session/session-manager.js +360 -424
- package/lib/internal/user-defaults-helpers.js +49 -39
- package/lib/internal/voice-pn-bridge.d.ts +114 -12
- package/lib/internal/voice-pn-bridge.js +212 -5
- package/lib/models/call-state.d.ts +46 -44
- package/lib/models/call-state.js +70 -68
- package/lib/models/call.d.ts +161 -133
- package/lib/models/call.js +454 -382
- package/lib/models/config.d.ts +11 -18
- package/lib/models/config.js +37 -35
- package/lib/models/connection-state.d.ts +10 -10
- package/lib/models/connection-state.js +16 -16
- package/lib/telnyx-voice-app.d.ts +28 -28
- package/lib/telnyx-voice-app.js +513 -480
- package/lib/telnyx-voip-client.d.ts +167 -167
- package/lib/telnyx-voip-client.js +385 -390
- package/package.json +115 -104
- package/src/callkit/callkit-coordinator.ts +830 -846
- package/src/hooks/useNetworkStateHandler.ts +0 -0
- package/src/internal/calls/call-state-controller.ts +407 -384
- package/src/internal/session/session-manager.ts +483 -467
- package/src/internal/voice-pn-bridge.ts +266 -18
- package/src/models/call-state.ts +105 -98
- package/src/models/call.ts +502 -388
- package/src/telnyx-voice-app.tsx +788 -690
- package/src/telnyx-voip-client.ts +551 -539
- package/src/types/telnyx-sdk.d.ts +93 -79
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports,
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CallStateController = void 0;
|
|
4
|
-
const rxjs_1 = require(
|
|
5
|
-
const operators_1 = require(
|
|
6
|
-
const call_1 = require(
|
|
7
|
-
const call_state_1 = require(
|
|
8
|
-
const callkit_coordinator_1 = require(
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const call_1 = require("../../models/call");
|
|
7
|
+
const call_state_1 = require("../../models/call-state");
|
|
8
|
+
const callkit_coordinator_1 = require("../../callkit/callkit-coordinator");
|
|
9
9
|
/**
|
|
10
10
|
* Central state machine for call management.
|
|
11
11
|
*
|
|
@@ -13,320 +13,276 @@ const callkit_coordinator_1 = require('../../callkit/callkit-coordinator');
|
|
|
13
13
|
* and provides reactive streams for call-related state changes.
|
|
14
14
|
*/
|
|
15
15
|
class CallStateController {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Observable stream of all current calls
|
|
26
|
-
*/
|
|
27
|
-
get calls$() {
|
|
28
|
-
return this._calls.asObservable().pipe((0, operators_1.distinctUntilChanged)());
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Observable stream of the currently active call
|
|
32
|
-
*/
|
|
33
|
-
get activeCall$() {
|
|
34
|
-
return this.calls$.pipe(
|
|
35
|
-
(0, operators_1.map)((calls) => {
|
|
36
|
-
// Find the first call that is not terminated (includes RINGING, CONNECTING, ACTIVE, HELD)
|
|
37
|
-
return (
|
|
38
|
-
calls.find(
|
|
39
|
-
(call) =>
|
|
40
|
-
call.currentState === call_state_1.TelnyxCallState.RINGING ||
|
|
41
|
-
call.currentState === call_state_1.TelnyxCallState.CONNECTING ||
|
|
42
|
-
call.currentState === call_state_1.TelnyxCallState.ACTIVE ||
|
|
43
|
-
call.currentState === call_state_1.TelnyxCallState.HELD
|
|
44
|
-
) || null
|
|
45
|
-
);
|
|
46
|
-
}),
|
|
47
|
-
(0, operators_1.distinctUntilChanged)()
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Current list of calls (synchronous access)
|
|
52
|
-
*/
|
|
53
|
-
get currentCalls() {
|
|
54
|
-
return this._calls.value;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Current active call (synchronous access)
|
|
58
|
-
*/
|
|
59
|
-
get currentActiveCall() {
|
|
60
|
-
const calls = this.currentCalls;
|
|
61
|
-
return (
|
|
62
|
-
calls.find(
|
|
63
|
-
(call) =>
|
|
64
|
-
call.currentState === call_state_1.TelnyxCallState.RINGING ||
|
|
65
|
-
call.currentState === call_state_1.TelnyxCallState.CONNECTING ||
|
|
66
|
-
call.currentState === call_state_1.TelnyxCallState.ACTIVE ||
|
|
67
|
-
call.currentState === call_state_1.TelnyxCallState.HELD
|
|
68
|
-
) || null
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Set a call to connecting state (used for push notification calls when answered via CallKit)
|
|
73
|
-
* @param callId The ID of the call to set to connecting state
|
|
74
|
-
*/
|
|
75
|
-
setCallConnecting(callId) {
|
|
76
|
-
const call = this._callMap.get(callId);
|
|
77
|
-
if (call) {
|
|
78
|
-
console.log('CallStateController: Setting call to connecting state:', callId);
|
|
79
|
-
call.setConnecting();
|
|
80
|
-
} else {
|
|
81
|
-
console.warn('CallStateController: Could not find call to set connecting:', callId);
|
|
16
|
+
constructor(_sessionManager) {
|
|
17
|
+
this._sessionManager = _sessionManager;
|
|
18
|
+
this._calls = new rxjs_1.BehaviorSubject([]);
|
|
19
|
+
this._callMap = new Map();
|
|
20
|
+
this._disposed = false;
|
|
21
|
+
console.log('🔧 CallStateController: Constructor called - instance created');
|
|
22
|
+
// Don't set up client listeners here - client doesn't exist yet
|
|
23
|
+
// Will be called when client is available
|
|
82
24
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
findCallByTelnyxCall(telnyxCall) {
|
|
89
|
-
for (const call of this._callMap.values()) {
|
|
90
|
-
if (call.telnyxCall === telnyxCall || call.telnyxCall.callId === telnyxCall.callId) {
|
|
91
|
-
return call;
|
|
92
|
-
}
|
|
25
|
+
/**
|
|
26
|
+
* Observable stream of all current calls
|
|
27
|
+
*/
|
|
28
|
+
get calls$() {
|
|
29
|
+
return this._calls.asObservable().pipe((0, operators_1.distinctUntilChanged)());
|
|
93
30
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Initiate a new outgoing call
|
|
108
|
-
*/
|
|
109
|
-
async newCall(destination, callerName, callerNumber, debug = false) {
|
|
110
|
-
if (this._disposed) {
|
|
111
|
-
throw new Error('CallStateController has been disposed');
|
|
31
|
+
/**
|
|
32
|
+
* Observable stream of the currently active call
|
|
33
|
+
*/
|
|
34
|
+
get activeCall$() {
|
|
35
|
+
return this.calls$.pipe((0, operators_1.map)((calls) => {
|
|
36
|
+
// Find the first call that is not terminated (includes RINGING, CONNECTING, ACTIVE, HELD)
|
|
37
|
+
return (calls.find((call) => call.currentState === call_state_1.TelnyxCallState.RINGING ||
|
|
38
|
+
call.currentState === call_state_1.TelnyxCallState.CONNECTING ||
|
|
39
|
+
call.currentState === call_state_1.TelnyxCallState.ACTIVE ||
|
|
40
|
+
call.currentState === call_state_1.TelnyxCallState.HELD) || null);
|
|
41
|
+
}), (0, operators_1.distinctUntilChanged)());
|
|
112
42
|
}
|
|
113
|
-
|
|
114
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Current list of calls (synchronous access)
|
|
45
|
+
*/
|
|
46
|
+
get currentCalls() {
|
|
47
|
+
return this._calls.value;
|
|
115
48
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const call = new call_1.Call(
|
|
126
|
-
telnyxCall,
|
|
127
|
-
telnyxCall.callId || this._generateCallId(),
|
|
128
|
-
destination,
|
|
129
|
-
false // outgoing call
|
|
130
|
-
);
|
|
131
|
-
// Add to our call tracking
|
|
132
|
-
this._addCall(call);
|
|
133
|
-
return call;
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error('Failed to create new call:', error);
|
|
136
|
-
throw error;
|
|
49
|
+
/**
|
|
50
|
+
* Current active call (synchronous access)
|
|
51
|
+
*/
|
|
52
|
+
get currentActiveCall() {
|
|
53
|
+
const calls = this.currentCalls;
|
|
54
|
+
return (calls.find((call) => call.currentState === call_state_1.TelnyxCallState.RINGING ||
|
|
55
|
+
call.currentState === call_state_1.TelnyxCallState.CONNECTING ||
|
|
56
|
+
call.currentState === call_state_1.TelnyxCallState.ACTIVE ||
|
|
57
|
+
call.currentState === call_state_1.TelnyxCallState.HELD) || null);
|
|
137
58
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return;
|
|
59
|
+
/**
|
|
60
|
+
* Set a call to connecting state (used for push notification calls when answered via CallKit)
|
|
61
|
+
* @param callId The ID of the call to set to connecting state
|
|
62
|
+
*/
|
|
63
|
+
setCallConnecting(callId) {
|
|
64
|
+
const call = this._callMap.get(callId);
|
|
65
|
+
if (call) {
|
|
66
|
+
console.log('CallStateController: Setting call to connecting state:', callId);
|
|
67
|
+
call.setConnecting();
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.warn('CallStateController: Could not find call to set connecting:', callId);
|
|
71
|
+
}
|
|
152
72
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
console.log('🔧 CallStateController: Setting up client listeners...');
|
|
165
|
-
if (!this._sessionManager.telnyxClient) {
|
|
166
|
-
console.log('🔧 CallStateController: No telnyxClient available yet, skipping listener setup');
|
|
167
|
-
return;
|
|
73
|
+
/**
|
|
74
|
+
* Find a call by its underlying Telnyx call ID
|
|
75
|
+
* @param telnyxCall The Telnyx call object to find
|
|
76
|
+
*/
|
|
77
|
+
findCallByTelnyxCall(telnyxCall) {
|
|
78
|
+
for (const call of this._callMap.values()) {
|
|
79
|
+
if (call.telnyxCall === telnyxCall || call.telnyxCall.callId === telnyxCall.callId) {
|
|
80
|
+
return call;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
168
84
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Handle incoming call
|
|
181
|
-
*/
|
|
182
|
-
_handleIncomingCall(telnyxCall, inviteMsg) {
|
|
183
|
-
const callId = telnyxCall.callId || this._generateCallId();
|
|
184
|
-
console.log('📞 CallStateController: Handling incoming call:', callId);
|
|
185
|
-
console.log('📞 CallStateController: TelnyxCall object:', telnyxCall);
|
|
186
|
-
console.log('📞 CallStateController: Invite message:', inviteMsg);
|
|
187
|
-
// Check if we already have this call
|
|
188
|
-
if (this._callMap.has(callId)) {
|
|
189
|
-
console.log('Call already exists:', callId);
|
|
190
|
-
return;
|
|
85
|
+
/**
|
|
86
|
+
* Initialize client listeners when the Telnyx client becomes available
|
|
87
|
+
* This should be called by the session manager after client creation
|
|
88
|
+
*/
|
|
89
|
+
initializeClientListeners() {
|
|
90
|
+
console.log('🔧 CallStateController: initializeClientListeners called');
|
|
91
|
+
console.log('🔧 CallStateController: Current client exists:', !!this._sessionManager.telnyxClient);
|
|
92
|
+
this._setupClientListeners();
|
|
93
|
+
// CallKit integration now handled by CallKitCoordinator
|
|
94
|
+
console.log('🔧 CallStateController: Using CallKitCoordinator for CallKit integration');
|
|
191
95
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Initiate a new outgoing call
|
|
98
|
+
*/
|
|
99
|
+
async newCall(destination, callerName, callerNumber, customHeaders) {
|
|
100
|
+
if (this._disposed) {
|
|
101
|
+
throw new Error('CallStateController has been disposed');
|
|
102
|
+
}
|
|
103
|
+
if (!this._sessionManager.telnyxClient) {
|
|
104
|
+
throw new Error('Telnyx client not available');
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
// Create the call using the Telnyx SDK
|
|
108
|
+
const callOptions = {
|
|
109
|
+
destinationNumber: destination,
|
|
110
|
+
callerIdName: callerName,
|
|
111
|
+
callerIdNumber: callerNumber,
|
|
112
|
+
customHeaders,
|
|
113
|
+
};
|
|
114
|
+
const telnyxCall = await this._sessionManager.telnyxClient.newCall(callOptions);
|
|
115
|
+
// Create our wrapper Call object
|
|
116
|
+
const call = new call_1.Call(telnyxCall, telnyxCall.callId || this._generateCallId(), destination, false, // outgoing call
|
|
117
|
+
false, // not reattached
|
|
118
|
+
callerName || destination, // use destination as fallback for caller name
|
|
119
|
+
callerNumber // original caller number
|
|
120
|
+
);
|
|
121
|
+
// Add to our call tracking
|
|
122
|
+
this._addCall(call);
|
|
123
|
+
return call;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
console.error('Failed to create new call:', error);
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
214
129
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
);
|
|
222
|
-
// Check if we're waiting for an invite (push notification scenario)
|
|
223
|
-
if (this._isWaitingForInvite && this._isWaitingForInvite()) {
|
|
224
|
-
console.log('Auto-accepting call from push notification');
|
|
225
|
-
call.answer().catch((error) => {
|
|
226
|
-
console.error('Failed to auto-accept call:', error);
|
|
227
|
-
});
|
|
228
|
-
if (this._onInviteAutoAccepted) {
|
|
229
|
-
this._onInviteAutoAccepted();
|
|
230
|
-
}
|
|
130
|
+
/**
|
|
131
|
+
* Set callbacks for waiting for invite logic (used for push notifications)
|
|
132
|
+
*/
|
|
133
|
+
setWaitingForInviteCallbacks(callbacks) {
|
|
134
|
+
this._isWaitingForInvite = callbacks.isWaitingForInvite;
|
|
135
|
+
this._onInviteAutoAccepted = callbacks.onInviteAutoAccepted;
|
|
231
136
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
console.warn(`Received state change for unknown call: ${callId}`);
|
|
137
|
+
/**
|
|
138
|
+
* Dispose of the controller and clean up resources
|
|
139
|
+
*/
|
|
140
|
+
dispose() {
|
|
141
|
+
if (this._disposed) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
this._disposed = true;
|
|
145
|
+
// Dispose of all calls
|
|
146
|
+
this.currentCalls.forEach((call) => call.dispose());
|
|
147
|
+
this._callMap.clear();
|
|
148
|
+
// CallKit cleanup is now handled by CallKitCoordinator automatically
|
|
149
|
+
this._calls.complete();
|
|
246
150
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Set up event listeners for the Telnyx client
|
|
153
|
+
*/
|
|
154
|
+
_setupClientListeners() {
|
|
155
|
+
console.log('🔧 CallStateController: Setting up client listeners...');
|
|
156
|
+
if (!this._sessionManager.telnyxClient) {
|
|
157
|
+
console.log('🔧 CallStateController: No telnyxClient available yet, skipping listener setup');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
console.log('🔧 CallStateController: TelnyxClient found, setting up incoming call listener');
|
|
161
|
+
console.log('🔧 CallStateController: Client instance:', this._sessionManager.telnyxClient.constructor.name);
|
|
162
|
+
// Listen for incoming calls
|
|
163
|
+
this._sessionManager.telnyxClient.on('telnyx.call.incoming', (telnyxCall, msg) => {
|
|
164
|
+
console.log('📞 CallStateController: Incoming call received:', telnyxCall.callId);
|
|
165
|
+
this._handleIncomingCall(telnyxCall, msg, false);
|
|
166
|
+
});
|
|
167
|
+
// Listen for reattached calls (after network reconnection)
|
|
168
|
+
this._sessionManager.telnyxClient.on('telnyx.call.reattached', (telnyxCall, msg) => {
|
|
169
|
+
console.log('📞 CallStateController: Reattached call received:', telnyxCall.callId);
|
|
170
|
+
this._handleIncomingCall(telnyxCall, msg, true);
|
|
171
|
+
});
|
|
172
|
+
// Verify listeners are set up
|
|
173
|
+
const incomingListeners = this._sessionManager.telnyxClient.listenerCount('telnyx.call.incoming');
|
|
174
|
+
const reattachedListeners = this._sessionManager.telnyxClient.listenerCount('telnyx.call.reattached');
|
|
175
|
+
console.log('🔧 CallStateController: Listeners registered - incoming:', incomingListeners, 'reattached:', reattachedListeners);
|
|
176
|
+
// Listen for other call events if needed
|
|
177
|
+
// this._sessionManager.telnyxClient.on('telnyx.call.stateChange', this._handleCallStateChange.bind(this));
|
|
178
|
+
console.log('🔧 CallStateController: Client listeners set up successfully');
|
|
259
179
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Handle incoming call or reattached call
|
|
182
|
+
*/
|
|
183
|
+
_handleIncomingCall(telnyxCall, inviteMsg, isReattached = false) {
|
|
184
|
+
const callId = telnyxCall.callId || this._generateCallId();
|
|
185
|
+
console.log('📞 CallStateController: Handling incoming call:', callId, 'isReattached:', isReattached);
|
|
186
|
+
console.log('📞 CallStateController: TelnyxCall object:', telnyxCall);
|
|
187
|
+
console.log('📞 CallStateController: Invite message:', inviteMsg);
|
|
188
|
+
// For reattached calls, remove existing call and create new one
|
|
189
|
+
if (isReattached && this._callMap.has(callId)) {
|
|
190
|
+
console.log('📞 CallStateController: Removing existing call for reattachment');
|
|
191
|
+
const existingCall = this._callMap.get(callId);
|
|
192
|
+
if (existingCall) {
|
|
193
|
+
console.log('📞 CallStateController: Existing call state before removal:', existingCall.currentState);
|
|
194
|
+
this._removeCall(callId);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Check if we already have this call (for non-reattached calls)
|
|
198
|
+
if (this._callMap.has(callId) && !isReattached) {
|
|
199
|
+
console.log('Call already exists:', callId);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Get caller information from the invite message (preferred) or fallback to TelnyxCall
|
|
203
|
+
let callerNumber = '';
|
|
204
|
+
let callerName = '';
|
|
205
|
+
if (inviteMsg && inviteMsg.params) {
|
|
206
|
+
callerNumber = inviteMsg.params.caller_id_number || '';
|
|
207
|
+
callerName = inviteMsg.params.caller_id_name || '';
|
|
208
|
+
console.log('📞 CallStateController: Extracted caller info from invite - Number:', callerNumber, 'Name:', callerName);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// Fallback to TelnyxCall properties
|
|
212
|
+
callerNumber = telnyxCall.remoteCallerIdNumber || '';
|
|
213
|
+
callerName = telnyxCall.remoteCallerIdName || '';
|
|
214
|
+
console.log('📞 CallStateController: Extracted caller info from TelnyxCall - Number:', callerNumber, 'Name:', callerName);
|
|
215
|
+
}
|
|
216
|
+
// Use smart fallbacks - prefer caller number over "Unknown"
|
|
217
|
+
const finalCallerNumber = callerNumber || 'Unknown Number';
|
|
218
|
+
const finalCallerName = callerName || callerNumber || 'Unknown Caller';
|
|
219
|
+
// Create our wrapper Call object
|
|
220
|
+
const call = new call_1.Call(telnyxCall, callId, finalCallerNumber, // Use caller number as destination for incoming calls
|
|
221
|
+
true, // incoming call
|
|
222
|
+
isReattached, // pass the reattached flag
|
|
223
|
+
finalCallerName, // use caller name or fallback to number
|
|
224
|
+
finalCallerNumber // use caller number
|
|
296
225
|
);
|
|
297
|
-
|
|
226
|
+
// Add to our call tracking - CallKit integration happens in _addCall
|
|
227
|
+
this._addCall(call);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Add a call to our tracking
|
|
231
|
+
*/
|
|
232
|
+
_addCall(call) {
|
|
233
|
+
this._callMap.set(call.callId, call);
|
|
234
|
+
const currentCalls = this.currentCalls;
|
|
235
|
+
currentCalls.push(call);
|
|
236
|
+
this._calls.next([...currentCalls]);
|
|
237
|
+
// Integrate with CallKit using CallKitCoordinator
|
|
238
|
+
if (callkit_coordinator_1.callKitCoordinator.isAvailable()) {
|
|
239
|
+
// Get the underlying TelnyxCall for CallKitCoordinator
|
|
240
|
+
const telnyxCall = call.telnyxCall;
|
|
241
|
+
// Check if this call already has CallKit integration (e.g., from push notification)
|
|
242
|
+
const existingCallKitUUID = callkit_coordinator_1.callKitCoordinator.getCallKitUUID(telnyxCall);
|
|
243
|
+
if (existingCallKitUUID) {
|
|
244
|
+
console.log('CallStateController: Call already has CallKit integration, skipping duplicate report:', existingCallKitUUID);
|
|
245
|
+
}
|
|
246
|
+
else if (call.isIncoming) {
|
|
247
|
+
// Handle incoming call with CallKit (only if not already integrated)
|
|
248
|
+
console.log('CallStateController: Reporting incoming call to CallKitCoordinator');
|
|
249
|
+
callkit_coordinator_1.callKitCoordinator.reportIncomingCall(telnyxCall, call.destination, call.destination);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
// Handle outgoing call with CallKit
|
|
253
|
+
console.log('CallStateController: Starting outgoing call with CallKitCoordinator');
|
|
254
|
+
callkit_coordinator_1.callKitCoordinator.startOutgoingCall(telnyxCall, call.destination, call.destination);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// Listen for call state changes - CallKitCoordinator handles this automatically
|
|
258
|
+
call.callState$.subscribe((state) => {
|
|
259
|
+
// CallKitCoordinator automatically updates CallKit via setupWebRTCCallListeners
|
|
260
|
+
console.log('CallStateController: Call state changed to:', state);
|
|
261
|
+
// Clean up when call ends
|
|
262
|
+
if (state === call_state_1.TelnyxCallState.ENDED || state === call_state_1.TelnyxCallState.FAILED) {
|
|
263
|
+
this._removeCall(call.callId);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Remove a call from our tracking
|
|
269
|
+
*/
|
|
270
|
+
_removeCall(callId) {
|
|
271
|
+
const call = this._callMap.get(callId);
|
|
272
|
+
if (call) {
|
|
273
|
+
console.log('CallStateController: Removing call:', callId);
|
|
274
|
+
// CallKit cleanup is handled automatically by CallKitCoordinator
|
|
275
|
+
call.dispose();
|
|
276
|
+
this._callMap.delete(callId);
|
|
277
|
+
const currentCalls = this.currentCalls.filter((c) => c.callId !== callId);
|
|
278
|
+
this._calls.next(currentCalls);
|
|
279
|
+
}
|
|
298
280
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (
|
|
305
|
-
state === call_state_1.TelnyxCallState.ENDED ||
|
|
306
|
-
state === call_state_1.TelnyxCallState.FAILED
|
|
307
|
-
) {
|
|
308
|
-
this._removeCall(call.callId);
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Remove a call from our tracking
|
|
314
|
-
*/
|
|
315
|
-
_removeCall(callId) {
|
|
316
|
-
const call = this._callMap.get(callId);
|
|
317
|
-
if (call) {
|
|
318
|
-
// CallKit cleanup is handled automatically by CallKitCoordinator
|
|
319
|
-
call.dispose();
|
|
320
|
-
this._callMap.delete(callId);
|
|
321
|
-
const currentCalls = this.currentCalls.filter((c) => c.callId !== callId);
|
|
322
|
-
this._calls.next(currentCalls);
|
|
281
|
+
/**
|
|
282
|
+
* Generate a unique call ID
|
|
283
|
+
*/
|
|
284
|
+
_generateCallId() {
|
|
285
|
+
return `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
323
286
|
}
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Generate a unique call ID
|
|
327
|
-
*/
|
|
328
|
-
_generateCallId() {
|
|
329
|
-
return `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
330
|
-
}
|
|
331
287
|
}
|
|
332
288
|
exports.CallStateController = CallStateController;
|