@telnyx/react-voice-commons-sdk 0.1.0
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/TelnyxVoiceCommons.podspec +32 -0
- package/ios/CallKitBridge.m +44 -0
- package/ios/CallKitBridge.swift +879 -0
- package/ios/README.md +211 -0
- package/ios/VoicePnBridge.m +31 -0
- package/ios/VoicePnBridge.swift +87 -0
- package/lib/callkit/callkit-coordinator.d.ts +126 -0
- package/lib/callkit/callkit-coordinator.js +728 -0
- package/lib/callkit/callkit.d.ts +49 -0
- package/lib/callkit/callkit.js +262 -0
- package/lib/callkit/index.d.ts +4 -0
- package/lib/callkit/index.js +15 -0
- package/lib/callkit/use-callkit-coordinator.d.ts +21 -0
- package/lib/callkit/use-callkit-coordinator.js +53 -0
- package/lib/callkit/use-callkit.d.ts +28 -0
- package/lib/callkit/use-callkit.js +279 -0
- package/lib/context/TelnyxVoiceContext.d.ts +18 -0
- package/lib/context/TelnyxVoiceContext.js +18 -0
- package/lib/hooks/use-callkit-coordinator.d.ts +13 -0
- package/lib/hooks/use-callkit-coordinator.js +48 -0
- package/lib/hooks/useAppReadyNotifier.d.ts +9 -0
- package/lib/hooks/useAppReadyNotifier.js +25 -0
- package/lib/hooks/useAppStateHandler.d.ts +16 -0
- package/lib/hooks/useAppStateHandler.js +105 -0
- package/lib/index.d.ts +24 -0
- package/lib/index.js +66 -0
- package/lib/internal/CallKitHandler.d.ts +17 -0
- package/lib/internal/CallKitHandler.js +110 -0
- package/lib/internal/callkit-manager.d.ts +69 -0
- package/lib/internal/callkit-manager.js +326 -0
- package/lib/internal/calls/call-state-controller.d.ts +92 -0
- package/lib/internal/calls/call-state-controller.js +294 -0
- package/lib/internal/session/session-manager.d.ts +87 -0
- package/lib/internal/session/session-manager.js +385 -0
- package/lib/internal/user-defaults-helpers.d.ts +10 -0
- package/lib/internal/user-defaults-helpers.js +69 -0
- package/lib/internal/voice-pn-bridge.d.ts +14 -0
- package/lib/internal/voice-pn-bridge.js +5 -0
- package/lib/models/call-state.d.ts +61 -0
- package/lib/models/call-state.js +87 -0
- package/lib/models/call.d.ts +145 -0
- package/lib/models/call.js +372 -0
- package/lib/models/config.d.ts +64 -0
- package/lib/models/config.js +92 -0
- package/lib/models/connection-state.d.ts +34 -0
- package/lib/models/connection-state.js +50 -0
- package/lib/telnyx-voice-app.d.ts +48 -0
- package/lib/telnyx-voice-app.js +486 -0
- package/lib/telnyx-voip-client.d.ts +184 -0
- package/lib/telnyx-voip-client.js +386 -0
- package/package.json +104 -0
- package/src/callkit/callkit-coordinator.ts +846 -0
- package/src/callkit/callkit.ts +322 -0
- package/src/callkit/index.ts +4 -0
- package/src/callkit/use-callkit.ts +345 -0
- package/src/context/TelnyxVoiceContext.tsx +33 -0
- package/src/hooks/use-callkit-coordinator.ts +60 -0
- package/src/hooks/useAppReadyNotifier.ts +25 -0
- package/src/hooks/useAppStateHandler.ts +134 -0
- package/src/index.ts +56 -0
- package/src/internal/CallKitHandler.tsx +149 -0
- package/src/internal/callkit-manager.ts +335 -0
- package/src/internal/calls/call-state-controller.ts +384 -0
- package/src/internal/session/session-manager.ts +467 -0
- package/src/internal/user-defaults-helpers.ts +58 -0
- package/src/internal/voice-pn-bridge.ts +18 -0
- package/src/models/call-state.ts +98 -0
- package/src/models/call.ts +388 -0
- package/src/models/config.ts +125 -0
- package/src/models/connection-state.ts +50 -0
- package/src/telnyx-voice-app.tsx +690 -0
- package/src/telnyx-voip-client.ts +475 -0
- package/src/types/telnyx-sdk.d.ts +79 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import CallKit, { CallEndReason } from '../callkit/callkit';
|
|
3
|
+
import { Call } from '../models/call';
|
|
4
|
+
import { TelnyxCallState } from '../models/call-state';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal CallKit integration manager for react-voice-commons.
|
|
8
|
+
*
|
|
9
|
+
* This class automatically handles CallKit integration for all calls
|
|
10
|
+
* without exposing complexity to the consumer components.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export class CallKitManager {
|
|
15
|
+
private _callMappings = new Map<string, string>(); // Call ID -> CallKit UUID
|
|
16
|
+
private _reverseCallMappings = new Map<string, string>(); // CallKit UUID -> Call ID
|
|
17
|
+
private _isEnabled = false;
|
|
18
|
+
private _callMap?: Map<string, Call>; // Reference to call map from call state controller
|
|
19
|
+
|
|
20
|
+
constructor() {
|
|
21
|
+
// DISABLED: Using external CallKit implementations (useCallKit, useCallKitCoordinator)
|
|
22
|
+
this._isEnabled = false; // Disable to prevent conflicts
|
|
23
|
+
console.log('🔧 CallKitManager: Initialized');
|
|
24
|
+
console.log('🔧 CallKitManager: Platform.OS =', Platform.OS);
|
|
25
|
+
console.log('🔧 CallKitManager: CallKit.isAvailable() =', CallKit.isAvailable());
|
|
26
|
+
console.log(
|
|
27
|
+
'🔧 CallKitManager: _isEnabled =',
|
|
28
|
+
this._isEnabled,
|
|
29
|
+
'(DISABLED to use external CallKit)'
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// DISABLED: Conflicts with external CallKit implementations (useCallKit, useCallKitCoordinator)
|
|
33
|
+
// if (this._isEnabled) {
|
|
34
|
+
// this._setupCallKitEventListeners();
|
|
35
|
+
// }
|
|
36
|
+
console.log(
|
|
37
|
+
'🔧 CallKitManager: Automatic CallKit integration DISABLED - using external CallKit implementations'
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Set up CallKit event listeners to handle user actions
|
|
43
|
+
*/
|
|
44
|
+
private _setupCallKitEventListeners(): void {
|
|
45
|
+
console.log('🔧 CallKitManager: Setting up CallKit event listeners');
|
|
46
|
+
|
|
47
|
+
// Listen for answer actions from CallKit
|
|
48
|
+
CallKit.onAnswerCall((event) => {
|
|
49
|
+
console.log('📞 CallKitManager: CallKit answer event received:', event);
|
|
50
|
+
this._handleCallKitAnswer(event.callUUID);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Listen for end actions from CallKit
|
|
54
|
+
CallKit.onEndCall((event) => {
|
|
55
|
+
console.log('📞 CallKitManager: CallKit end event received:', event);
|
|
56
|
+
this._handleCallKitEnd(event.callUUID);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
console.log('🔧 CallKitManager: CallKit event listeners set up');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Initialize CallKit integration
|
|
64
|
+
*/
|
|
65
|
+
initialize(onAnswerCall: (callId: string) => void, onEndCall: (callId: string) => void) {
|
|
66
|
+
if (!this._isEnabled) return;
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
// This would need to be called from a React component context
|
|
70
|
+
// For now, we'll handle this differently in the call-state-controller
|
|
71
|
+
console.log('CallKitManager: CallKit integration initialized');
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.warn('CallKitManager: Failed to initialize CallKit:', error);
|
|
74
|
+
this._isEnabled = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Handle outgoing call - start CallKit session
|
|
80
|
+
*/
|
|
81
|
+
async handleOutgoingCall(call: Call): Promise<string | null> {
|
|
82
|
+
console.log('🔵 CallKitManager.handleOutgoingCall() CALLED');
|
|
83
|
+
console.log('🔵 CallKitManager: call.callId =', call.callId);
|
|
84
|
+
console.log('🔵 CallKitManager: call.destination =', call.destination);
|
|
85
|
+
console.log('🔵 CallKitManager: call.isIncoming =', call.isIncoming);
|
|
86
|
+
console.log('🔵 CallKitManager: _isEnabled =', this._isEnabled);
|
|
87
|
+
|
|
88
|
+
if (!this._isEnabled) {
|
|
89
|
+
console.log('🔴 CallKitManager: CallKit NOT ENABLED - skipping outgoing call');
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
console.log('🔵 CallKitManager: Starting CallKit session for outgoing call:', call.callId);
|
|
95
|
+
|
|
96
|
+
const callKitUUID = CallKit.generateCallUUID();
|
|
97
|
+
console.log('🔵 CallKitManager: Generated CallKit UUID:', callKitUUID);
|
|
98
|
+
|
|
99
|
+
// Call the native CallKit bridge
|
|
100
|
+
console.log('🔵 CallKitManager: Calling native CallKit.startOutgoingCall...');
|
|
101
|
+
const success = await CallKit.startOutgoingCall(
|
|
102
|
+
callKitUUID,
|
|
103
|
+
call.destination,
|
|
104
|
+
call.destination // Using destination as display name for now
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (success) {
|
|
108
|
+
console.log('� CallKitManager: Native CallKit.startOutgoingCall SUCCESS!');
|
|
109
|
+
this._callMappings.set(call.callId, callKitUUID);
|
|
110
|
+
console.log('� CallKitManager: Stored call mapping:', call.callId, '->', callKitUUID);
|
|
111
|
+
return callKitUUID;
|
|
112
|
+
} else {
|
|
113
|
+
console.log('� CallKitManager: Native CallKit.startOutgoingCall FAILED');
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('🔴 CallKitManager: Failed to start outgoing call:', error);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Handle incoming call - show CallKit UI
|
|
124
|
+
*/
|
|
125
|
+
async handleIncomingCall(call: Call): Promise<string | null> {
|
|
126
|
+
console.log('🟡 CallKitManager.handleIncomingCall() CALLED');
|
|
127
|
+
console.log('🟡 CallKitManager: call.callId =', call.callId);
|
|
128
|
+
console.log('🟡 CallKitManager: call.destination =', call.destination);
|
|
129
|
+
console.log('🟡 CallKitManager: call.isIncoming =', call.isIncoming);
|
|
130
|
+
console.log('🟡 CallKitManager: _isEnabled =', this._isEnabled);
|
|
131
|
+
|
|
132
|
+
if (!this._isEnabled) {
|
|
133
|
+
console.log('🔴 CallKitManager: CallKit NOT ENABLED - skipping incoming call');
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
console.log('🟡 CallKitManager: Showing CallKit UI for incoming call:', call.callId);
|
|
139
|
+
|
|
140
|
+
const callKitUUID = CallKit.generateCallUUID();
|
|
141
|
+
console.log('🟡 CallKitManager: Generated CallKit UUID for incoming call:', callKitUUID);
|
|
142
|
+
|
|
143
|
+
// Call the native CallKit bridge
|
|
144
|
+
console.log('🟡 CallKitManager: Calling native CallKit.reportIncomingCall...');
|
|
145
|
+
|
|
146
|
+
// For incoming calls, the call.destination contains the caller number
|
|
147
|
+
// We should use a more descriptive name if available
|
|
148
|
+
const handle = call.destination;
|
|
149
|
+
const displayName = call.destination; // For now, use the number as display name too
|
|
150
|
+
|
|
151
|
+
console.log('🟡 CallKitManager: Using handle:', handle, 'displayName:', displayName);
|
|
152
|
+
|
|
153
|
+
const success = await CallKit.reportIncomingCall(callKitUUID, handle, displayName);
|
|
154
|
+
|
|
155
|
+
if (success) {
|
|
156
|
+
console.log('� CallKitManager: Native CallKit.reportIncomingCall SUCCESS!');
|
|
157
|
+
this._callMappings.set(call.callId, callKitUUID);
|
|
158
|
+
console.log(
|
|
159
|
+
'� CallKitManager: Stored incoming call mapping:',
|
|
160
|
+
call.callId,
|
|
161
|
+
'->',
|
|
162
|
+
callKitUUID
|
|
163
|
+
);
|
|
164
|
+
return callKitUUID;
|
|
165
|
+
} else {
|
|
166
|
+
console.log('� CallKitManager: Native CallKit.reportIncomingCall FAILED');
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error('🔴 CallKitManager: Failed to show incoming call:', error);
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Update call state in CallKit
|
|
177
|
+
*/
|
|
178
|
+
async updateCallState(call: Call, state: TelnyxCallState): Promise<void> {
|
|
179
|
+
if (!this._isEnabled) return;
|
|
180
|
+
|
|
181
|
+
const callKitUUID = this._callMappings.get(call.callId);
|
|
182
|
+
if (!callKitUUID) return;
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
console.log(`🔧 CallKitManager: Updating CallKit state for call ${call.callId} to ${state}`);
|
|
186
|
+
console.log(`🔧 CallKitManager: CallKit UUID: ${callKitUUID}`);
|
|
187
|
+
|
|
188
|
+
switch (state) {
|
|
189
|
+
case TelnyxCallState.ACTIVE:
|
|
190
|
+
console.log('🟢 CallKitManager: Reporting call connected to CallKit');
|
|
191
|
+
await CallKit.reportCallConnected(callKitUUID);
|
|
192
|
+
break;
|
|
193
|
+
case TelnyxCallState.ENDED:
|
|
194
|
+
console.log('🔴 CallKitManager: Reporting call ended to CallKit (remote ended)');
|
|
195
|
+
await CallKit.reportCallEnded(callKitUUID, CallEndReason.RemoteEnded);
|
|
196
|
+
this._callMappings.delete(call.callId);
|
|
197
|
+
break;
|
|
198
|
+
case TelnyxCallState.FAILED:
|
|
199
|
+
console.log('🔴 CallKitManager: Reporting call ended to CallKit (failed)');
|
|
200
|
+
await CallKit.reportCallEnded(callKitUUID, CallEndReason.Failed);
|
|
201
|
+
this._callMappings.delete(call.callId);
|
|
202
|
+
break;
|
|
203
|
+
case TelnyxCallState.RINGING:
|
|
204
|
+
console.log('🟡 CallKitManager: Call ringing - no CallKit update needed');
|
|
205
|
+
break;
|
|
206
|
+
default:
|
|
207
|
+
console.log(`🔧 CallKitManager: Unhandled state: ${state}`);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error('🔴 CallKitManager: Failed to update call state:', error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* End CallKit session
|
|
217
|
+
*/
|
|
218
|
+
async endCall(call: Call): Promise<void> {
|
|
219
|
+
if (!this._isEnabled) return;
|
|
220
|
+
|
|
221
|
+
const callKitUUID = this._callMappings.get(call.callId);
|
|
222
|
+
if (!callKitUUID) return;
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
console.log('🔴 CallKitManager: Ending CallKit session for call:', call.callId);
|
|
226
|
+
console.log('🔴 CallKitManager: CallKit UUID:', callKitUUID);
|
|
227
|
+
|
|
228
|
+
// Report call ended with user-initiated reason
|
|
229
|
+
await CallKit.reportCallEnded(callKitUUID, CallEndReason.RemoteEnded);
|
|
230
|
+
this._callMappings.delete(call.callId);
|
|
231
|
+
|
|
232
|
+
console.log('🔴 CallKitManager: CallKit session ended successfully');
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error('🔴 CallKitManager: Failed to end call:', error);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Handle CallKit answer action
|
|
240
|
+
*/
|
|
241
|
+
private _handleCallKitAnswer(callKitUUID: string): void {
|
|
242
|
+
console.log('📞 CallKitManager: Handling CallKit answer for UUID:', callKitUUID);
|
|
243
|
+
|
|
244
|
+
// Find the call ID from the CallKit UUID
|
|
245
|
+
const callId = this._reverseCallMappings.get(callKitUUID);
|
|
246
|
+
if (!callId) {
|
|
247
|
+
console.error('🔴 CallKitManager: No call found for CallKit UUID:', callKitUUID);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
console.log('📞 CallKitManager: Found call ID:', callId);
|
|
252
|
+
|
|
253
|
+
// Find the call object and answer it
|
|
254
|
+
if (this._callMap) {
|
|
255
|
+
const call = this._callMap.get(callId);
|
|
256
|
+
if (call) {
|
|
257
|
+
console.log('📞 CallKitManager: Answering call:', callId);
|
|
258
|
+
call.answer();
|
|
259
|
+
} else {
|
|
260
|
+
console.error('🔴 CallKitManager: Call object not found for ID:', callId);
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
console.error('🔴 CallKitManager: Call map not available');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Handle CallKit end action
|
|
269
|
+
*/
|
|
270
|
+
private _handleCallKitEnd(callKitUUID: string): void {
|
|
271
|
+
console.log('📞 CallKitManager: Handling CallKit end for UUID:', callKitUUID);
|
|
272
|
+
|
|
273
|
+
// Find the call ID from the CallKit UUID
|
|
274
|
+
const callId = this._reverseCallMappings.get(callKitUUID);
|
|
275
|
+
if (!callId) {
|
|
276
|
+
console.error('🔴 CallKitManager: No call found for CallKit UUID:', callKitUUID);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
console.log('📞 CallKitManager: Found call ID:', callId);
|
|
281
|
+
|
|
282
|
+
// Find the call object and hang up
|
|
283
|
+
if (this._callMap) {
|
|
284
|
+
const call = this._callMap.get(callId);
|
|
285
|
+
if (call) {
|
|
286
|
+
console.log('📞 CallKitManager: Hanging up call:', callId);
|
|
287
|
+
call.hangup();
|
|
288
|
+
} else {
|
|
289
|
+
console.error('🔴 CallKitManager: Call object not found for ID:', callId);
|
|
290
|
+
}
|
|
291
|
+
} else {
|
|
292
|
+
console.error('🔴 CallKitManager: Call map not available');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Set the call map reference for handling CallKit actions
|
|
298
|
+
*/
|
|
299
|
+
setCallMap(callMap: Map<string, Call>): void {
|
|
300
|
+
this._callMap = callMap;
|
|
301
|
+
console.log('🔧 CallKitManager: Call map reference set');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Check if CallKit is available
|
|
306
|
+
*/
|
|
307
|
+
get isAvailable(): boolean {
|
|
308
|
+
return this._isEnabled;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get CallKit UUID for a call
|
|
313
|
+
*/
|
|
314
|
+
getCallKitUUID(callId: string): string | null {
|
|
315
|
+
return this._callMappings.get(callId) || null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Generate a UUID for CallKit
|
|
320
|
+
*/
|
|
321
|
+
private generateUUID(): string {
|
|
322
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
323
|
+
const r = (Math.random() * 16) | 0;
|
|
324
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
325
|
+
return v.toString(16);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Dispose of the CallKit manager
|
|
331
|
+
*/
|
|
332
|
+
dispose() {
|
|
333
|
+
this._callMappings.clear();
|
|
334
|
+
}
|
|
335
|
+
}
|