@capgo/capacitor-twilio-voice 8.2.8 → 8.2.10
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/android/src/main/java/ee/forgr/capacitor_twilio_voice/CapacitorTwilioVoicePlugin.java
CHANGED
|
@@ -75,7 +75,7 @@ import org.json.JSONObject;
|
|
|
75
75
|
)
|
|
76
76
|
public class CapacitorTwilioVoicePlugin extends Plugin {
|
|
77
77
|
|
|
78
|
-
private final String pluginVersion = "8.2.
|
|
78
|
+
private final String pluginVersion = "8.2.10";
|
|
79
79
|
|
|
80
80
|
private static final String TAG = "CapacitorTwilioVoice";
|
|
81
81
|
private static final String PREF_ACCESS_TOKEN = "twilio_access_token";
|
|
@@ -28,7 +28,7 @@ public protocol PushKitEventDelegate: AnyObject {
|
|
|
28
28
|
*/
|
|
29
29
|
@objc(CapacitorTwilioVoicePlugin)
|
|
30
30
|
public class CapacitorTwilioVoicePlugin: CAPPlugin, CAPBridgedPlugin, PushKitEventDelegate {
|
|
31
|
-
private let pluginVersion: String = "8.2.
|
|
31
|
+
private let pluginVersion: String = "8.2.10"
|
|
32
32
|
|
|
33
33
|
public let identifier = "CapacitorTwilioVoicePlugin"
|
|
34
34
|
public let jsName = "CapacitorTwilioVoice"
|
|
@@ -57,6 +57,7 @@ public class CapacitorTwilioVoicePlugin: CAPPlugin, CAPBridgedPlugin, PushKitEve
|
|
|
57
57
|
private var activeCall: Call?
|
|
58
58
|
private var callKitProvider: CXProvider?
|
|
59
59
|
private let callKitCallController = CXCallController()
|
|
60
|
+
private let callObserver = CXCallObserver()
|
|
60
61
|
private var userInitiatedDisconnect: Bool = false
|
|
61
62
|
private var audioDevice = DefaultAudioDevice()
|
|
62
63
|
private var callKitCompletionCallback: ((Bool) -> Void)?
|
|
@@ -97,6 +98,7 @@ public class CapacitorTwilioVoicePlugin: CAPPlugin, CAPBridgedPlugin, PushKitEve
|
|
|
97
98
|
setupCallKit()
|
|
98
99
|
setupAudioDevice()
|
|
99
100
|
setupNotifications()
|
|
101
|
+
callObserver.setDelegate(self, queue: nil)
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
private func setupCallKit() {
|
|
@@ -117,8 +119,7 @@ public class CapacitorTwilioVoicePlugin: CAPPlugin, CAPBridgedPlugin, PushKitEve
|
|
|
117
119
|
try audioSession.setCategory(.playAndRecord,
|
|
118
120
|
mode: .voiceChat,
|
|
119
121
|
options: [.allowBluetooth, .allowBluetoothA2DP, .allowAirPlay])
|
|
120
|
-
|
|
121
|
-
NSLog("Audio session configured successfully")
|
|
122
|
+
NSLog("Audio session category configured")
|
|
122
123
|
} catch {
|
|
123
124
|
NSLog("Failed to configure audio session: \(error.localizedDescription)")
|
|
124
125
|
}
|
|
@@ -151,10 +152,10 @@ public class CapacitorTwilioVoicePlugin: CAPPlugin, CAPBridgedPlugin, PushKitEve
|
|
|
151
152
|
NSLog("Media services were reset, reconfiguring audio session")
|
|
152
153
|
setupAudioSession()
|
|
153
154
|
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
if let call = getActiveCall(), !call.isOnHold {
|
|
156
|
+
audioDevice.isEnabled = true
|
|
157
|
+
}
|
|
156
158
|
|
|
157
|
-
// Notify listeners about the reset
|
|
158
159
|
notifyListeners("audioSessionReset", data: nil)
|
|
159
160
|
}
|
|
160
161
|
|
|
@@ -168,27 +169,13 @@ public class CapacitorTwilioVoicePlugin: CAPPlugin, CAPBridgedPlugin, PushKitEve
|
|
|
168
169
|
switch type {
|
|
169
170
|
case .began:
|
|
170
171
|
NSLog("Audio session interruption began")
|
|
171
|
-
|
|
172
|
+
if activeCalls.isEmpty && activeCallInvites.isEmpty {
|
|
173
|
+
audioDevice.isEnabled = false
|
|
174
|
+
}
|
|
172
175
|
notifyListeners("audioSessionInterrupted", data: ["type": "began"])
|
|
173
176
|
|
|
174
177
|
case .ended:
|
|
175
178
|
NSLog("Audio session interruption ended")
|
|
176
|
-
|
|
177
|
-
// Check if we should resume
|
|
178
|
-
if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
|
|
179
|
-
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
|
|
180
|
-
if options.contains(.shouldResume) {
|
|
181
|
-
do {
|
|
182
|
-
try AVAudioSession.sharedInstance().setActive(true)
|
|
183
|
-
audioDevice.isEnabled = true
|
|
184
|
-
NSLog("Audio session resumed after interruption")
|
|
185
|
-
notifyListeners("audioSessionResumed", data: nil)
|
|
186
|
-
} catch {
|
|
187
|
-
NSLog("Failed to resume audio session: \(error.localizedDescription)")
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
179
|
notifyListeners("audioSessionInterrupted", data: ["type": "ended"])
|
|
193
180
|
|
|
194
181
|
@unknown default:
|
|
@@ -708,42 +695,14 @@ public class CapacitorTwilioVoicePlugin: CAPPlugin, CAPBridgedPlugin, PushKitEve
|
|
|
708
695
|
private func toggleAudioRoute(toSpeaker: Bool) {
|
|
709
696
|
audioDevice.block = {
|
|
710
697
|
do {
|
|
711
|
-
let audioSession = AVAudioSession.sharedInstance()
|
|
712
|
-
|
|
713
|
-
// Ensure audio session is active before changing routing
|
|
714
|
-
if !audioSession.isOtherAudioPlaying {
|
|
715
|
-
try audioSession.setActive(true)
|
|
716
|
-
}
|
|
717
|
-
|
|
718
698
|
if toSpeaker {
|
|
719
|
-
try
|
|
699
|
+
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
|
|
720
700
|
} else {
|
|
721
|
-
try
|
|
701
|
+
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
|
|
722
702
|
}
|
|
723
|
-
|
|
724
703
|
NSLog("Audio route changed to: \(toSpeaker ? "speaker" : "earpiece")")
|
|
725
704
|
} catch {
|
|
726
705
|
NSLog("Failed to change audio route: \(error.localizedDescription)")
|
|
727
|
-
|
|
728
|
-
// Try to recover by reconfiguring the audio session
|
|
729
|
-
do {
|
|
730
|
-
let audioSession = AVAudioSession.sharedInstance()
|
|
731
|
-
try audioSession.setCategory(.playAndRecord,
|
|
732
|
-
mode: .voiceChat,
|
|
733
|
-
options: [.allowBluetooth, .allowBluetoothA2DP, .allowAirPlay])
|
|
734
|
-
try audioSession.setActive(true)
|
|
735
|
-
|
|
736
|
-
// Retry the audio route change
|
|
737
|
-
if toSpeaker {
|
|
738
|
-
try audioSession.overrideOutputAudioPort(.speaker)
|
|
739
|
-
} else {
|
|
740
|
-
try audioSession.overrideOutputAudioPort(.none)
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
NSLog("Audio route recovered and changed to: \(toSpeaker ? "speaker" : "earpiece")")
|
|
744
|
-
} catch {
|
|
745
|
-
NSLog("Failed to recover audio route: \(error.localizedDescription)")
|
|
746
|
-
}
|
|
747
706
|
}
|
|
748
707
|
}
|
|
749
708
|
audioDevice.block()
|
|
@@ -1131,17 +1090,16 @@ extension CapacitorTwilioVoicePlugin: CXProviderDelegate {
|
|
|
1131
1090
|
public func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
|
1132
1091
|
NSLog("CallKit activated audio session")
|
|
1133
1092
|
|
|
1134
|
-
// Configure the audio session for VoIP calls
|
|
1135
1093
|
do {
|
|
1136
1094
|
try audioSession.setCategory(.playAndRecord,
|
|
1137
1095
|
mode: .voiceChat,
|
|
1138
1096
|
options: [.allowBluetooth, .allowBluetoothA2DP, .allowAirPlay])
|
|
1139
|
-
audioDevice.isEnabled = true
|
|
1140
|
-
NSLog("Audio session activated and configured for call")
|
|
1141
1097
|
} catch {
|
|
1142
1098
|
NSLog("Failed to configure audio session during activation: \(error.localizedDescription)")
|
|
1143
|
-
audioDevice.isEnabled = true // Still try to enable the device
|
|
1144
1099
|
}
|
|
1100
|
+
|
|
1101
|
+
audioDevice.isEnabled = true
|
|
1102
|
+
NSLog("Audio device enabled after CallKit activation")
|
|
1145
1103
|
}
|
|
1146
1104
|
|
|
1147
1105
|
public func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
|
|
@@ -1265,6 +1223,46 @@ extension CapacitorTwilioVoicePlugin: CXProviderDelegate {
|
|
|
1265
1223
|
}
|
|
1266
1224
|
}
|
|
1267
1225
|
|
|
1226
|
+
|
|
1227
|
+
// MARK: - CXCallObserverDelegate
|
|
1228
|
+
|
|
1229
|
+
extension CapacitorTwilioVoicePlugin: CXCallObserverDelegate {
|
|
1230
|
+
public func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
|
|
1231
|
+
guard let voipCall = getActiveCall(),
|
|
1232
|
+
let voipCallUuid = voipCall.uuid,
|
|
1233
|
+
activeCalls[voipCallUuid.uuidString] != nil,
|
|
1234
|
+
call.hasEnded,
|
|
1235
|
+
call.uuid != voipCallUuid,
|
|
1236
|
+
callObserver.calls.count == 1,
|
|
1237
|
+
voipCall.isOnHold,
|
|
1238
|
+
callObserver.calls.first?.uuid == voipCallUuid else {
|
|
1239
|
+
return
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
NSLog("External call ended, scheduling VoIP call unhold")
|
|
1243
|
+
|
|
1244
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
|
1245
|
+
guard let self = self,
|
|
1246
|
+
let call = self.getActiveCall(),
|
|
1247
|
+
call.isOnHold,
|
|
1248
|
+
let uuid = call.uuid else {
|
|
1249
|
+
return
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
let unholdAction = CXSetHeldCallAction(call: uuid, onHold: false)
|
|
1253
|
+
let transaction = CXTransaction(action: unholdAction)
|
|
1254
|
+
|
|
1255
|
+
self.callKitCallController.request(transaction) { error in
|
|
1256
|
+
if let error = error {
|
|
1257
|
+
NSLog("Failed to unhold VoIP call after external call ended: \(error.localizedDescription)")
|
|
1258
|
+
} else {
|
|
1259
|
+
NSLog("Successfully unheld VoIP call after external call ended")
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1268
1266
|
// MARK: - AVAudioPlayerDelegate
|
|
1269
1267
|
|
|
1270
1268
|
extension CapacitorTwilioVoicePlugin: AVAudioPlayerDelegate {
|