voice-react-native-sdk 1.6.2-fork.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.
Files changed (227) hide show
  1. package/LICENSE +206 -0
  2. package/README.md +179 -0
  3. package/android/build.gradle +113 -0
  4. package/android/gradle.properties +29 -0
  5. package/android/src/main/AndroidManifest.xml +30 -0
  6. package/android/src/main/java/com/twiliovoicereactnative/AudioSwitchManager.java +141 -0
  7. package/android/src/main/java/com/twiliovoicereactnative/CallListenerProxy.java +186 -0
  8. package/android/src/main/java/com/twiliovoicereactnative/CallMessageListenerProxy.java +103 -0
  9. package/android/src/main/java/com/twiliovoicereactnative/CallRecordDatabase.java +183 -0
  10. package/android/src/main/java/com/twiliovoicereactnative/CommonConstants.java +195 -0
  11. package/android/src/main/java/com/twiliovoicereactnative/ConfigurationProperties.java +41 -0
  12. package/android/src/main/java/com/twiliovoicereactnative/Constants.java +23 -0
  13. package/android/src/main/java/com/twiliovoicereactnative/ExpoActivityLifecycleListener.java +27 -0
  14. package/android/src/main/java/com/twiliovoicereactnative/ExpoApplicationLifecycleListener.java +14 -0
  15. package/android/src/main/java/com/twiliovoicereactnative/ExpoModule.kt +36 -0
  16. package/android/src/main/java/com/twiliovoicereactnative/ExpoPackage.java +20 -0
  17. package/android/src/main/java/com/twiliovoicereactnative/JSEventEmitter.java +98 -0
  18. package/android/src/main/java/com/twiliovoicereactnative/MediaPlayerManager.java +58 -0
  19. package/android/src/main/java/com/twiliovoicereactnative/NotificationUtility.java +363 -0
  20. package/android/src/main/java/com/twiliovoicereactnative/ReactNativeArgumentsSerializer.java +276 -0
  21. package/android/src/main/java/com/twiliovoicereactnative/SDKLog.java +74 -0
  22. package/android/src/main/java/com/twiliovoicereactnative/StatsListenerProxy.java +178 -0
  23. package/android/src/main/java/com/twiliovoicereactnative/TwilioVoiceReactNativeModule.java +778 -0
  24. package/android/src/main/java/com/twiliovoicereactnative/TwilioVoiceReactNativePackage.java +28 -0
  25. package/android/src/main/java/com/twiliovoicereactnative/VoiceActivityProxy.java +101 -0
  26. package/android/src/main/java/com/twiliovoicereactnative/VoiceApplicationProxy.java +133 -0
  27. package/android/src/main/java/com/twiliovoicereactnative/VoiceFirebaseMessagingService.java +88 -0
  28. package/android/src/main/java/com/twiliovoicereactnative/VoiceService.java +403 -0
  29. package/android/src/main/res/drawable/answered_call_small_icon.png +0 -0
  30. package/android/src/main/res/drawable/ic_launcher_round.png +0 -0
  31. package/android/src/main/res/drawable/ic_launcher_sdk.png +0 -0
  32. package/android/src/main/res/drawable/incoming_call_small_icon.png +0 -0
  33. package/android/src/main/res/drawable/outgoing_call_small_icon.png +0 -0
  34. package/android/src/main/res/raw/disconnect.wav +0 -0
  35. package/android/src/main/res/raw/incoming.wav +0 -0
  36. package/android/src/main/res/raw/outgoing.wav +0 -0
  37. package/android/src/main/res/raw/ringtone.wav +0 -0
  38. package/android/src/main/res/raw/silent.wav +0 -0
  39. package/android/src/main/res/values/colors.xml +11 -0
  40. package/android/src/main/res/values/config.xml +5 -0
  41. package/android/src/main/res/values/dimens.xml +7 -0
  42. package/android/src/main/res/values/strings.xml +25 -0
  43. package/android/src/main/res/values/styles.xml +10 -0
  44. package/android/src/main/res/values-night/colors.xml +11 -0
  45. package/expo-config-plugin/android.js +191 -0
  46. package/expo-config-plugin/ios.js +22 -0
  47. package/expo-module.config.json +6 -0
  48. package/ios/TwilioVoicePushRegistry.h +19 -0
  49. package/ios/TwilioVoicePushRegistry.m +72 -0
  50. package/ios/TwilioVoiceReactNative+CallInvite.m +56 -0
  51. package/ios/TwilioVoiceReactNative+CallKit.m +533 -0
  52. package/ios/TwilioVoiceReactNative+CallMessage.m +81 -0
  53. package/ios/TwilioVoiceReactNative.h +74 -0
  54. package/ios/TwilioVoiceReactNative.m +1046 -0
  55. package/ios/TwilioVoiceReactNative.xcodeproj/project.pbxproj +328 -0
  56. package/ios/TwilioVoiceReactNativeConstants.h +200 -0
  57. package/ios/Utilities/TwilioVoiceStatsReport.h +175 -0
  58. package/lib/commonjs/AudioDevice.js +101 -0
  59. package/lib/commonjs/AudioDevice.js.map +1 -0
  60. package/lib/commonjs/Call.js +765 -0
  61. package/lib/commonjs/Call.js.map +1 -0
  62. package/lib/commonjs/CallInvite.js +452 -0
  63. package/lib/commonjs/CallInvite.js.map +1 -0
  64. package/lib/commonjs/CallMessage/CallMessage.js +54 -0
  65. package/lib/commonjs/CallMessage/CallMessage.js.map +1 -0
  66. package/lib/commonjs/CallMessage/IncomingCallMessage.js +120 -0
  67. package/lib/commonjs/CallMessage/IncomingCallMessage.js.map +1 -0
  68. package/lib/commonjs/CallMessage/OutgoingCallMessage.js +148 -0
  69. package/lib/commonjs/CallMessage/OutgoingCallMessage.js.map +1 -0
  70. package/lib/commonjs/ExpoModule.js +69 -0
  71. package/lib/commonjs/ExpoModule.js.map +1 -0
  72. package/lib/commonjs/Voice.js +611 -0
  73. package/lib/commonjs/Voice.js.map +1 -0
  74. package/lib/commonjs/common.js +26 -0
  75. package/lib/commonjs/common.js.map +1 -0
  76. package/lib/commonjs/constants.js +158 -0
  77. package/lib/commonjs/constants.js.map +1 -0
  78. package/lib/commonjs/error/InvalidArgumentError.js +32 -0
  79. package/lib/commonjs/error/InvalidArgumentError.js.map +1 -0
  80. package/lib/commonjs/error/InvalidStateError.js +33 -0
  81. package/lib/commonjs/error/InvalidStateError.js.map +1 -0
  82. package/lib/commonjs/error/TwilioError.js +38 -0
  83. package/lib/commonjs/error/TwilioError.js.map +1 -0
  84. package/lib/commonjs/error/UnsupportedPlatformError.js +33 -0
  85. package/lib/commonjs/error/UnsupportedPlatformError.js.map +1 -0
  86. package/lib/commonjs/error/generated.js +2343 -0
  87. package/lib/commonjs/error/generated.js.map +1 -0
  88. package/lib/commonjs/error/index.js +112 -0
  89. package/lib/commonjs/error/index.js.map +1 -0
  90. package/lib/commonjs/error/utility.js +37 -0
  91. package/lib/commonjs/error/utility.js.map +1 -0
  92. package/lib/commonjs/index.js +95 -0
  93. package/lib/commonjs/index.js.map +1 -0
  94. package/lib/commonjs/type/AudioDevice.js +6 -0
  95. package/lib/commonjs/type/AudioDevice.js.map +1 -0
  96. package/lib/commonjs/type/Call.js +6 -0
  97. package/lib/commonjs/type/Call.js.map +1 -0
  98. package/lib/commonjs/type/CallInvite.js +6 -0
  99. package/lib/commonjs/type/CallInvite.js.map +1 -0
  100. package/lib/commonjs/type/CallKit.js +30 -0
  101. package/lib/commonjs/type/CallKit.js.map +1 -0
  102. package/lib/commonjs/type/CallMessage.js +6 -0
  103. package/lib/commonjs/type/CallMessage.js.map +1 -0
  104. package/lib/commonjs/type/Error.js +6 -0
  105. package/lib/commonjs/type/Error.js.map +1 -0
  106. package/lib/commonjs/type/NativeModule.js +6 -0
  107. package/lib/commonjs/type/NativeModule.js.map +1 -0
  108. package/lib/commonjs/type/RTCStats.js +29 -0
  109. package/lib/commonjs/type/RTCStats.js.map +1 -0
  110. package/lib/commonjs/type/Voice.js +6 -0
  111. package/lib/commonjs/type/Voice.js.map +1 -0
  112. package/lib/commonjs/type/common.js +2 -0
  113. package/lib/commonjs/type/common.js.map +1 -0
  114. package/lib/module/AudioDevice.js +97 -0
  115. package/lib/module/AudioDevice.js.map +1 -0
  116. package/lib/module/Call.js +766 -0
  117. package/lib/module/Call.js.map +1 -0
  118. package/lib/module/CallInvite.js +450 -0
  119. package/lib/module/CallInvite.js.map +1 -0
  120. package/lib/module/CallMessage/CallMessage.js +51 -0
  121. package/lib/module/CallMessage/CallMessage.js.map +1 -0
  122. package/lib/module/CallMessage/IncomingCallMessage.js +116 -0
  123. package/lib/module/CallMessage/IncomingCallMessage.js.map +1 -0
  124. package/lib/module/CallMessage/OutgoingCallMessage.js +154 -0
  125. package/lib/module/CallMessage/OutgoingCallMessage.js.map +1 -0
  126. package/lib/module/ExpoModule.js +58 -0
  127. package/lib/module/ExpoModule.js.map +1 -0
  128. package/lib/module/Voice.js +598 -0
  129. package/lib/module/Voice.js.map +1 -0
  130. package/lib/module/common.js +11 -0
  131. package/lib/module/common.js.map +1 -0
  132. package/lib/module/constants.js +151 -0
  133. package/lib/module/constants.js.map +1 -0
  134. package/lib/module/error/InvalidArgumentError.js +23 -0
  135. package/lib/module/error/InvalidArgumentError.js.map +1 -0
  136. package/lib/module/error/InvalidStateError.js +24 -0
  137. package/lib/module/error/InvalidStateError.js.map +1 -0
  138. package/lib/module/error/TwilioError.js +29 -0
  139. package/lib/module/error/TwilioError.js.map +1 -0
  140. package/lib/module/error/UnsupportedPlatformError.js +24 -0
  141. package/lib/module/error/UnsupportedPlatformError.js.map +1 -0
  142. package/lib/module/error/generated.js +2315 -0
  143. package/lib/module/error/generated.js.map +1 -0
  144. package/lib/module/error/index.js +6 -0
  145. package/lib/module/error/index.js.map +1 -0
  146. package/lib/module/error/utility.js +27 -0
  147. package/lib/module/error/utility.js.map +1 -0
  148. package/lib/module/index.js +23 -0
  149. package/lib/module/index.js.map +1 -0
  150. package/lib/module/type/AudioDevice.js +2 -0
  151. package/lib/module/type/AudioDevice.js.map +1 -0
  152. package/lib/module/type/Call.js +2 -0
  153. package/lib/module/type/Call.js.map +1 -0
  154. package/lib/module/type/CallInvite.js +2 -0
  155. package/lib/module/type/CallInvite.js.map +1 -0
  156. package/lib/module/type/CallKit.js +22 -0
  157. package/lib/module/type/CallKit.js.map +1 -0
  158. package/lib/module/type/CallMessage.js +2 -0
  159. package/lib/module/type/CallMessage.js.map +1 -0
  160. package/lib/module/type/Error.js +2 -0
  161. package/lib/module/type/Error.js.map +1 -0
  162. package/lib/module/type/NativeModule.js +2 -0
  163. package/lib/module/type/NativeModule.js.map +1 -0
  164. package/lib/module/type/RTCStats.js +21 -0
  165. package/lib/module/type/RTCStats.js.map +1 -0
  166. package/lib/module/type/Voice.js +2 -0
  167. package/lib/module/type/Voice.js.map +1 -0
  168. package/lib/module/type/common.js +2 -0
  169. package/lib/module/type/common.js.map +1 -0
  170. package/lib/typescript/AudioDevice.d.ts +74 -0
  171. package/lib/typescript/Call.d.ts +874 -0
  172. package/lib/typescript/CallInvite.d.ts +484 -0
  173. package/lib/typescript/CallMessage/CallMessage.d.ts +53 -0
  174. package/lib/typescript/CallMessage/IncomingCallMessage.d.ts +75 -0
  175. package/lib/typescript/CallMessage/OutgoingCallMessage.d.ts +198 -0
  176. package/lib/typescript/ExpoModule.d.ts +13 -0
  177. package/lib/typescript/Voice.d.ts +620 -0
  178. package/lib/typescript/common.d.ts +11 -0
  179. package/lib/typescript/constants.d.ts +148 -0
  180. package/lib/typescript/error/InvalidArgumentError.d.ts +11 -0
  181. package/lib/typescript/error/InvalidStateError.d.ts +12 -0
  182. package/lib/typescript/error/TwilioError.d.ts +14 -0
  183. package/lib/typescript/error/UnsupportedPlatformError.d.ts +12 -0
  184. package/lib/typescript/error/generated.d.ts +1558 -0
  185. package/lib/typescript/error/index.d.ts +5 -0
  186. package/lib/typescript/error/utility.d.ts +12 -0
  187. package/lib/typescript/index.d.ts +18 -0
  188. package/lib/typescript/type/AudioDevice.d.ts +15 -0
  189. package/lib/typescript/type/Call.d.ts +59 -0
  190. package/lib/typescript/type/CallInvite.d.ts +40 -0
  191. package/lib/typescript/type/CallKit.d.ts +60 -0
  192. package/lib/typescript/type/CallMessage.d.ts +20 -0
  193. package/lib/typescript/type/Error.d.ts +9 -0
  194. package/lib/typescript/type/NativeModule.d.ts +59 -0
  195. package/lib/typescript/type/RTCStats.d.ts +91 -0
  196. package/lib/typescript/type/Voice.d.ts +16 -0
  197. package/lib/typescript/type/common.d.ts +15 -0
  198. package/package.json +167 -0
  199. package/src/AudioDevice.tsx +88 -0
  200. package/src/Call.tsx +1343 -0
  201. package/src/CallInvite.tsx +757 -0
  202. package/src/CallMessage/CallMessage.ts +83 -0
  203. package/src/CallMessage/IncomingCallMessage.ts +104 -0
  204. package/src/CallMessage/OutgoingCallMessage.ts +308 -0
  205. package/src/ExpoModule.ts +59 -0
  206. package/src/Voice.tsx +1010 -0
  207. package/src/common.ts +16 -0
  208. package/src/constants.ts +193 -0
  209. package/src/error/InvalidArgumentError.ts +19 -0
  210. package/src/error/InvalidStateError.ts +19 -0
  211. package/src/error/TwilioError.ts +22 -0
  212. package/src/error/UnsupportedPlatformError.ts +19 -0
  213. package/src/error/generated.ts +2277 -0
  214. package/src/error/index.ts +18 -0
  215. package/src/error/utility.ts +36 -0
  216. package/src/index.tsx +24 -0
  217. package/src/type/AudioDevice.ts +18 -0
  218. package/src/type/Call.ts +102 -0
  219. package/src/type/CallInvite.ts +59 -0
  220. package/src/type/CallKit.ts +61 -0
  221. package/src/type/CallMessage.ts +31 -0
  222. package/src/type/Error.ts +11 -0
  223. package/src/type/NativeModule.ts +93 -0
  224. package/src/type/RTCStats.ts +99 -0
  225. package/src/type/Voice.ts +31 -0
  226. package/src/type/common.ts +16 -0
  227. package/twilio-voice-react-native.podspec +22 -0
@@ -0,0 +1,533 @@
1
+ //
2
+ // TwilioVoiceReactNative+CallKit.m
3
+ // TwilioVoiceReactNative
4
+ //
5
+ // Copyright © 2022 Twilio, Inc. All rights reserved.
6
+ //
7
+
8
+ @import CallKit;
9
+ @import TwilioVoice;
10
+
11
+ #import "TwilioVoiceReactNative.h"
12
+ #import "TwilioVoiceReactNativeConstants.h"
13
+
14
+ NSString * const kDefaultCallKitConfigurationName = @"Twilio Voice React Native";
15
+
16
+ @interface TwilioVoiceReactNative (CallKit) <CXProviderDelegate, TVOCallDelegate, AVAudioPlayerDelegate>
17
+
18
+ @end
19
+
20
+ @implementation TwilioVoiceReactNative (CallKit)
21
+
22
+ #pragma mark - CallKit helper methods
23
+
24
+ - (void)initializeCallKit {
25
+ [self initializeCallKitWithConfiguration:nil];
26
+ }
27
+
28
+ - (void)initializeCallKitWithConfiguration:(NSDictionary *)configuration {
29
+ CXProviderConfiguration *callKitConfiguration = [CXProviderConfiguration new];
30
+
31
+ if (configuration[kTwilioVoiceReactNativeCallKitMaximumCallGroups]) {
32
+ callKitConfiguration.maximumCallGroups = [configuration[kTwilioVoiceReactNativeCallKitMaximumCallGroups] intValue];
33
+ } else {
34
+ callKitConfiguration.maximumCallGroups = 1;
35
+ }
36
+
37
+ if (configuration[kTwilioVoiceReactNativeCallKitMaximumCallsPerCallGroup]) {
38
+ callKitConfiguration.maximumCallsPerCallGroup = [configuration[kTwilioVoiceReactNativeCallKitMaximumCallsPerCallGroup] intValue];
39
+ } else {
40
+ callKitConfiguration.maximumCallsPerCallGroup = 1;
41
+ }
42
+
43
+ float version = [[UIDevice currentDevice].systemVersion floatValue];
44
+ if (version > 11.0 && configuration[kTwilioVoiceReactNativeCallKitIncludesCallsInRecents]) {
45
+ callKitConfiguration.includesCallsInRecents = [configuration[kTwilioVoiceReactNativeCallKitIncludesCallsInRecents] boolValue];
46
+ }
47
+
48
+ if (configuration[kTwilioVoiceReactNativeCallKitSupportedHandleTypes]) {
49
+ NSSet *supportedHandleTypes = [NSSet setWithArray:configuration[kTwilioVoiceReactNativeCallKitSupportedHandleTypes]];
50
+ callKitConfiguration.supportedHandleTypes = supportedHandleTypes;
51
+ } else {
52
+ callKitConfiguration.supportedHandleTypes = [NSSet setWithArray:@[@(CXHandleTypeGeneric), @(CXHandleTypePhoneNumber)]];
53
+ }
54
+
55
+ if (configuration[kTwilioVoiceReactNativeCallKitIconTemplateImageData] && [configuration[kTwilioVoiceReactNativeCallKitIconTemplateImageData] isKindOfClass:[NSString class]]) {
56
+ UIImage *icon = [UIImage imageNamed:configuration[kTwilioVoiceReactNativeCallKitIconTemplateImageData]];
57
+ callKitConfiguration.iconTemplateImageData = UIImagePNGRepresentation(icon);
58
+ }
59
+
60
+ if (configuration[kTwilioVoiceReactNativeCallKitRingtoneSound] && [configuration[kTwilioVoiceReactNativeCallKitRingtoneSound] isKindOfClass:[NSString class]]) {
61
+ callKitConfiguration.ringtoneSound = configuration[kTwilioVoiceReactNativeCallKitRingtoneSound];
62
+ }
63
+
64
+ self.callKitProvider = [[CXProvider alloc] initWithConfiguration:callKitConfiguration];
65
+ [self.callKitProvider setDelegate:self queue:nil];
66
+ self.callKitCallController = [CXCallController new];
67
+ }
68
+
69
+ - (NSString *)getDisplayName:(NSString *)template
70
+ customParameters:(NSDictionary<NSString *, NSString *> *)customParameters {
71
+ NSString *processedTemplate = template;
72
+ for (NSString *paramKey in customParameters) {
73
+ NSString *paramValue = customParameters[paramKey];
74
+ NSString *wrappedParamKey = [NSString stringWithFormat:@"${%@}", paramKey];
75
+ processedTemplate = [processedTemplate stringByReplacingOccurrencesOfString:wrappedParamKey withString:paramValue];
76
+ }
77
+ return processedTemplate;
78
+ }
79
+
80
+ - (void)reportNewIncomingCall:(TVOCallInvite *)callInvite {
81
+ NSString *handleName = callInvite.from;
82
+ if (handleName == nil) {
83
+ handleName = @"Unknown Caller";
84
+ }
85
+
86
+ NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
87
+ NSString *preferenceKey = @"incomingCallContactHandleTemplate";
88
+ if ([preferences objectForKey:preferenceKey] != nil) {
89
+ const NSString *preferenceVal = [preferences stringForKey:preferenceKey];
90
+ if ([preferenceVal length] > 0) {
91
+ handleName = [self getDisplayName:preferenceVal customParameters:[callInvite customParameters]];
92
+ }
93
+ }
94
+
95
+ CXHandle *callHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handleName];
96
+
97
+ CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
98
+ callUpdate.remoteHandle = callHandle;
99
+ callUpdate.localizedCallerName = handleName;
100
+ callUpdate.supportsDTMF = YES;
101
+ callUpdate.supportsHolding = YES;
102
+ callUpdate.supportsGrouping = NO;
103
+ callUpdate.supportsUngrouping = NO;
104
+ callUpdate.hasVideo = NO;
105
+
106
+ [self.callKitProvider reportNewIncomingCallWithUUID:callInvite.uuid update:callUpdate completion:^(NSError *error) {
107
+ if (!error) {
108
+ NSLog(@"Incoming call successfully reported.");
109
+ } else {
110
+ NSLog(@"Failed to report incoming call: %@.", error);
111
+ }
112
+ }];
113
+ }
114
+
115
+ - (void)answerCallInvite:(NSUUID *)uuid
116
+ completion:(void(^)(BOOL success))completionHandler {
117
+ self.callKitCompletionCallback = completionHandler;
118
+ CXAnswerCallAction *answerCallAction = [[CXAnswerCallAction alloc] initWithCallUUID:uuid];
119
+ CXTransaction *transaction = [[CXTransaction alloc] initWithAction:answerCallAction];
120
+
121
+ [self.callKitCallController requestTransaction:transaction completion:^(NSError *error) {
122
+ if (error) {
123
+ NSLog(@"Failed to submit answer-call transaction request: %@", error);
124
+ } else {
125
+ NSLog(@"Answer-call transaction successfully done");
126
+ }
127
+ }];
128
+ }
129
+
130
+ - (void)endCallWithUuid:(NSUUID *)uuid {
131
+ CXEndCallAction *endCallAction = [[CXEndCallAction alloc] initWithCallUUID:uuid];
132
+ CXTransaction *transaction = [[CXTransaction alloc] initWithAction:endCallAction];
133
+
134
+ [self.callKitCallController requestTransaction:transaction completion:^(NSError *error) {
135
+ if (error) {
136
+ NSLog(@"Failed to submit end-call transaction request: %@", error);
137
+ } else {
138
+ NSLog(@"End-call transaction successfully done");
139
+ }
140
+ }];
141
+ }
142
+
143
+ - (void)makeCallWithAccessToken:(NSString *)accessToken
144
+ params:(NSDictionary *)params
145
+ contactHandle:(NSString *)contactHandle {
146
+ self.accessToken = accessToken;
147
+ self.twimlParams = params;
148
+
149
+ NSString *handle = @"Default Contact";
150
+ if ([contactHandle length] > 0) {
151
+ handle = contactHandle;
152
+ }
153
+
154
+ CXHandle *callHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle];
155
+ NSUUID *uuid = [NSUUID UUID];
156
+ CXStartCallAction *startCallAction = [[CXStartCallAction alloc] initWithCallUUID:uuid handle:callHandle];
157
+ CXTransaction *transaction = [[CXTransaction alloc] initWithAction:startCallAction];
158
+
159
+ [self.callKitCallController requestTransaction:transaction completion:^(NSError *error) {
160
+ if (error) {
161
+ NSLog(@"StartCallAction transaction request failed: %@", [error localizedDescription]);
162
+ } else {
163
+ NSLog(@"StartCallAction transaction request successful");
164
+
165
+ CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
166
+
167
+ callUpdate.remoteHandle = callHandle;
168
+ callUpdate.supportsDTMF = YES;
169
+ callUpdate.supportsHolding = YES;
170
+ callUpdate.supportsGrouping = NO;
171
+ callUpdate.supportsUngrouping = NO;
172
+ callUpdate.hasVideo = NO;
173
+
174
+ [self.callKitProvider reportCallWithUUID:uuid updated:callUpdate];
175
+ }
176
+ }];
177
+ }
178
+
179
+ - (void)performVoiceCallWithUUID:(NSUUID *)uuid
180
+ client:(NSString *)client
181
+ completion:(void(^)(BOOL success))completionHandler {
182
+ TVOConnectOptions *connectOptions = [TVOConnectOptions optionsWithAccessToken:self.accessToken block:^(TVOConnectOptionsBuilder *builder) {
183
+ builder.params = self.twimlParams;
184
+ builder.uuid = uuid;
185
+ builder.callMessageDelegate = self;
186
+ }];
187
+ TVOCall *call = [TwilioVoiceSDK connectWithOptions:connectOptions delegate:self];
188
+ if (call) {
189
+ self.callMap[call.uuid.UUIDString] = call;
190
+ self.callPromiseResolver([self callInfo:call]);
191
+ }
192
+ self.callKitCompletionCallback = completionHandler;
193
+ }
194
+
195
+ - (void)performAnswerVoiceCallWithUUID:(NSUUID *)uuid
196
+ completion:(void(^)(BOOL success))completionHandler {
197
+ NSAssert(self.callInviteMap[uuid.UUIDString], @"No call invite");
198
+
199
+ TVOCallInvite *callInvite = self.callInviteMap[uuid.UUIDString];
200
+ TVOAcceptOptions *acceptOptions = [TVOAcceptOptions optionsWithCallInvite:callInvite block:^(TVOAcceptOptionsBuilder *builder) {
201
+ builder.uuid = uuid;
202
+ builder.callMessageDelegate = self;
203
+ }];
204
+
205
+ TVOCall *call = [callInvite acceptWithOptions:acceptOptions delegate:self];
206
+
207
+ if (!call) {
208
+ completionHandler(NO);
209
+ } else {
210
+ self.callMap[call.uuid.UUIDString] = call;
211
+ }
212
+
213
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCallInvite
214
+ body:@{
215
+ kTwilioVoiceReactNativeCallInviteEventKeyType: kTwilioVoiceReactNativeCallInviteEventTypeValueAccepted,
216
+ kTwilioVoiceReactNativeCallInviteEventKeyCallSid: callInvite.callSid,
217
+ kTwilioVoiceReactNativeEventKeyCallInvite: [self callInviteInfo:callInvite]}];
218
+ }
219
+
220
+ - (void)updateCall:(NSString *)uuid callerHandle:(NSString *)handle {
221
+ CXHandle *callHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle];
222
+ CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
223
+ callUpdate.remoteHandle = callHandle;
224
+ callUpdate.localizedCallerName = handle;
225
+ callUpdate.supportsDTMF = YES;
226
+ callUpdate.supportsHolding = YES;
227
+ callUpdate.supportsGrouping = NO;
228
+ callUpdate.supportsUngrouping = NO;
229
+ callUpdate.hasVideo = NO;
230
+
231
+ dispatch_async(dispatch_get_main_queue(), ^{
232
+ [self.callKitProvider reportCallWithUUID:[[NSUUID alloc] initWithUUIDString:uuid] updated:callUpdate];
233
+ });
234
+ }
235
+
236
+ #pragma mark - CXProviderDelegate
237
+
238
+ - (void)providerDidReset:(CXProvider *)provider {
239
+ [TwilioVoiceReactNative twilioAudioDevice].enabled = NO;
240
+ }
241
+
242
+ - (void)providerDidBegin:(CXProvider *)provider {
243
+
244
+ }
245
+
246
+ - (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession {
247
+ [TwilioVoiceReactNative twilioAudioDevice].enabled = YES;
248
+ }
249
+
250
+ - (void)provider:(CXProvider *)provider didDeactivateAudioSession:(AVAudioSession *)audioSession {
251
+ [TwilioVoiceReactNative twilioAudioDevice].enabled = NO;
252
+ }
253
+
254
+ - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action {
255
+ if (self.callMap[action.callUUID.UUIDString]) {
256
+ TVOCall *call = self.callMap[action.callUUID.UUIDString];
257
+ [call disconnect];
258
+ } else if (self.callInviteMap[action.callUUID.UUIDString]) {
259
+ TVOCallInvite *callInvite = self.callInviteMap[action.callUUID.UUIDString];
260
+ [callInvite reject];
261
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCallInvite
262
+ body:@{
263
+ kTwilioVoiceReactNativeCallInviteEventKeyType: kTwilioVoiceReactNativeCallInviteEventTypeValueRejected,
264
+ kTwilioVoiceReactNativeCallInviteEventKeyCallSid: callInvite.callSid,
265
+ kTwilioVoiceReactNativeEventKeyCallInvite: [self callInviteInfo:callInvite]}];
266
+ [self.callInviteMap removeObjectForKey:action.callUUID.UUIDString];
267
+ }
268
+
269
+ [action fulfill];
270
+ }
271
+
272
+ - (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action {
273
+ [TwilioVoiceReactNative twilioAudioDevice].enabled = NO;
274
+ [TwilioVoiceReactNative twilioAudioDevice].block();
275
+
276
+ [self.callKitProvider reportOutgoingCallWithUUID:action.callUUID startedConnectingAtDate:[NSDate date]];
277
+
278
+ __weak typeof(self) weakSelf = self;
279
+ [self performVoiceCallWithUUID:action.callUUID client:nil completion:^(BOOL success) {
280
+ __strong typeof(self) strongSelf = weakSelf;
281
+ if (success) {
282
+ NSLog(@"performVoiceCallWithUUID successful");
283
+ [strongSelf.callKitProvider reportOutgoingCallWithUUID:action.callUUID connectedAtDate:[NSDate date]];
284
+ } else {
285
+ NSLog(@"performVoiceCallWithUUID failed");
286
+ }
287
+ }];
288
+
289
+ [action fulfill];
290
+ }
291
+
292
+ - (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
293
+ [TwilioVoiceReactNative twilioAudioDevice].enabled = NO;
294
+ [TwilioVoiceReactNative twilioAudioDevice].block();
295
+
296
+ [self performAnswerVoiceCallWithUUID:action.callUUID completion:^(BOOL success) {
297
+ if (success) {
298
+ NSLog(@"performAnswerVoiceCallWithUUID successful");
299
+ } else {
300
+ NSLog(@"performAnswerVoiceCallWithUUID failed");
301
+ }
302
+ }];
303
+
304
+ [action fulfill];
305
+ }
306
+
307
+ - (void)provider:(CXProvider *)provider performSetHeldCallAction:(CXSetHeldCallAction *)action {
308
+ if (self.callMap[action.callUUID.UUIDString]) {
309
+ TVOCall *call = self.callMap[action.callUUID.UUIDString];
310
+ [call setOnHold:action.isOnHold];
311
+ [action fulfill];
312
+ } else {
313
+ [action fail];
314
+ }
315
+ }
316
+
317
+ - (void)provider:(CXProvider *)provider performSetMutedCallAction:(CXSetMutedCallAction *)action {
318
+ if (self.callMap[action.callUUID.UUIDString]) {
319
+ TVOCall *call = self.callMap[action.callUUID.UUIDString];
320
+ [call setMuted:action.isMuted];
321
+ [action fulfill];
322
+ } else {
323
+ [action fail];
324
+ }
325
+ }
326
+
327
+ - (void)provider:(CXProvider *)provider performPlayDTMFCallAction:(CXPlayDTMFCallAction *)action {
328
+ if (self.callMap[action.callUUID.UUIDString]) {
329
+ TVOCall *call = self.callMap[action.callUUID.UUIDString];
330
+ [call sendDigits:action.digits];
331
+ [action fulfill];
332
+ } else {
333
+ [action fail];
334
+ }
335
+ }
336
+
337
+ #pragma mark - TVOCallDelegate
338
+
339
+ - (void)callDidStartRinging:(TVOCall *)call {
340
+ [self playRingback];
341
+
342
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCall
343
+ body:@{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventRinging,
344
+ kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call]}];
345
+ }
346
+
347
+ - (void)callDidConnect:(TVOCall *)call {
348
+ self.callConnectMap[call.uuid.UUIDString] = [self getSimplifiedISO8601FormattedTimestamp:[NSDate date]];
349
+
350
+ [self stopRingback];
351
+
352
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCall
353
+ body:@{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventConnected,
354
+ kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call]}];
355
+
356
+ if (self.callKitCompletionCallback) {
357
+ self.callKitCompletionCallback(YES);
358
+ self.callKitCompletionCallback = nil;
359
+ }
360
+ }
361
+
362
+ - (void)call:(TVOCall *)call didDisconnectWithError:(NSError *)error {
363
+ NSDictionary *messageBody = [NSDictionary dictionary];
364
+ if (error) {
365
+ messageBody = @{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventDisconnected,
366
+ kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call],
367
+ kTwilioVoiceReactNativeVoiceErrorKeyError: @{kTwilioVoiceReactNativeVoiceErrorKeyCode: @(error.code),
368
+ kTwilioVoiceReactNativeVoiceErrorKeyMessage: [error localizedDescription]}};
369
+ } else {
370
+ messageBody = @{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventDisconnected,
371
+ kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call]};
372
+ }
373
+
374
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCall body:messageBody];
375
+
376
+ if (!self.userInitiatedDisconnect) {
377
+ CXCallEndedReason reason = CXCallEndedReasonRemoteEnded;
378
+ if (error) {
379
+ reason = CXCallEndedReasonFailed;
380
+ }
381
+
382
+ [self.callKitProvider reportCallWithUUID:call.uuid endedAtDate:[NSDate date] reason:reason];
383
+ }
384
+
385
+ [self callDisconnected:call];
386
+ }
387
+
388
+ - (void)call:(TVOCall *)call didFailToConnectWithError:(NSError *)error {
389
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCall
390
+ body:@{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventConnectFailure,
391
+ kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call],
392
+ kTwilioVoiceReactNativeVoiceErrorKeyError: @{kTwilioVoiceReactNativeVoiceErrorKeyCode: @(error.code),
393
+ kTwilioVoiceReactNativeVoiceErrorKeyMessage: [error localizedDescription]}}];
394
+
395
+ if (self.callKitCompletionCallback) {
396
+ self.callKitCompletionCallback(NO);
397
+ self.callKitCompletionCallback = nil;
398
+ }
399
+ [self.callKitProvider reportCallWithUUID:call.uuid endedAtDate:[NSDate date] reason:CXCallEndedReasonFailed];
400
+
401
+ [self callDisconnected:call];
402
+ }
403
+
404
+ - (void)callDisconnected:(TVOCall *)call {
405
+ for (NSString *uuidKey in [self.callMap allKeys]) {
406
+ TVOCall *activeCall = self.callMap[uuidKey];
407
+ if (activeCall == call) {
408
+ [self.callMap removeObjectForKey:uuidKey];
409
+ [self.callConnectMap removeObjectForKey:call.uuid.UUIDString];
410
+ break;
411
+ }
412
+ }
413
+
414
+ // Remove the corresponding call invite only when the incoming call is finished.
415
+ [self.callInviteMap removeObjectForKey:call.uuid.UUIDString];
416
+
417
+ [self stopRingback];
418
+ self.userInitiatedDisconnect = NO;
419
+ }
420
+
421
+ - (void)call:(TVOCall *)call isReconnectingWithError:(NSError *)error {
422
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCall
423
+ body:@{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventReconnecting,
424
+ kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call],
425
+ kTwilioVoiceReactNativeVoiceErrorKeyError: @{kTwilioVoiceReactNativeVoiceErrorKeyCode: @(error.code),
426
+ kTwilioVoiceReactNativeVoiceErrorKeyMessage: [error localizedDescription]}}];
427
+ }
428
+
429
+ - (void)callDidReconnect:(TVOCall *)call {
430
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCall
431
+ body:@{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventReconnected,
432
+ kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call]}];
433
+ }
434
+
435
+ - (void)call:(TVOCall *)call
436
+ didReceiveQualityWarnings:(NSSet<NSNumber *> *)currentWarnings
437
+ previousWarnings:(NSSet<NSNumber *> *)previousWarnings {
438
+ NSMutableArray<NSString *> *currentWarningEvents = [NSMutableArray array];
439
+ for (NSNumber *warning in currentWarnings) {
440
+ NSString *event = [self warningNameWithNumber:warning];
441
+ [currentWarningEvents addObject:event];
442
+ }
443
+
444
+ NSMutableArray<NSString *> *previousWarningEvents = [NSMutableArray array];
445
+ for (NSNumber *warning in previousWarnings) {
446
+ NSString *event = [self warningNameWithNumber:warning];
447
+ [previousWarningEvents addObject:event];
448
+ }
449
+
450
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCall
451
+ body:@{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventQualityWarningsChanged,
452
+ kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call],
453
+ kTwilioVoiceReactNativeCallEventCurrentWarnings: currentWarningEvents,
454
+ kTwilioVoiceReactNativeCallEventPreviousWarnings: previousWarningEvents}];
455
+ }
456
+
457
+ #pragma mark - Ringback
458
+
459
+ - (void)playRingback {
460
+ NSString *ringtonePath = [[NSBundle mainBundle] pathForResource:@"ringtone" ofType:@"wav"];
461
+ if ([ringtonePath length] <= 0) {
462
+ NSLog(@"Can't find sound file");
463
+ return;
464
+ }
465
+
466
+ NSError *error;
467
+ self.ringbackPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:ringtonePath] error:&error];
468
+ if (error != nil) {
469
+ NSLog(@"Failed to initialize audio player: %@", error);
470
+ } else {
471
+ self.ringbackPlayer.delegate = self;
472
+ self.ringbackPlayer.numberOfLoops = -1;
473
+
474
+ self.ringbackPlayer.volume = 1.0f;
475
+ [self.ringbackPlayer play];
476
+ }
477
+ }
478
+
479
+ - (void)stopRingback {
480
+ if (!self.ringbackPlayer.isPlaying) {
481
+ return;
482
+ }
483
+
484
+ [self.ringbackPlayer stop];
485
+ }
486
+
487
+ - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
488
+ if (flag) {
489
+ NSLog(@"Audio player finished playing successfully");
490
+ } else {
491
+ NSLog(@"Audio player finished playing with some error");
492
+ }
493
+ }
494
+
495
+ - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error {
496
+ NSLog(@"Decode error occurred: %@", error);
497
+ }
498
+
499
+ #pragma mark - Warning event conversion
500
+
501
+ - (NSString *)warningNameWithNumber:(NSNumber *)warning {
502
+ if ([warning intValue] < 0 || [warning intValue] > 4) {
503
+ NSLog(@"Warning number out of TVOCallQualityWarning range");
504
+ return @"undefined";
505
+ }
506
+
507
+ TVOCallQualityWarning warningValue = [warning intValue];
508
+ switch (warningValue) {
509
+ case TVOCallQualityWarningHighRtt:
510
+ return @"high-rtt";
511
+ case TVOCallQualityWarningHighJitter:
512
+ return @"high-jitter";
513
+ case TVOCallQualityWarningHighPacketsLostFraction:
514
+ return @"high-packets-lost-fraction";
515
+ case TVOCallQualityWarningLowMos:
516
+ return @"low-mos";
517
+ case TVOCallQualityWarningConstantAudioInputLevel:
518
+ return @"constant-audio-input-level";
519
+ default:
520
+ return @"undefined";
521
+ }
522
+ }
523
+
524
+ - (NSString *)getSimplifiedISO8601FormattedTimestamp:(NSDate *)date {
525
+ NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
526
+ NSLocale *locale = [NSLocale currentLocale];
527
+ [formatter setLocale:locale];
528
+ [formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSSZ"];
529
+
530
+ return [formatter stringFromDate:date];
531
+ }
532
+
533
+ @end
@@ -0,0 +1,81 @@
1
+ //
2
+ // TwilioVoiceReactNative+CallMessage.m
3
+ // TwilioVoiceReactNative
4
+ //
5
+ // Copyright © 2024 Twilio, Inc. All rights reserved.
6
+ //
7
+
8
+ @import TwilioVoice;
9
+
10
+ #import "TwilioVoiceReactNative.h"
11
+ #import "TwilioVoiceReactNativeConstants.h"
12
+
13
+ @interface TwilioVoiceReactNative (CallMessage) <TVOCallMessageDelegate>
14
+
15
+ @end
16
+
17
+ @implementation TwilioVoiceReactNative (CallMessage)
18
+
19
+ #pragma mark - TVOCallMessageDelegate (Call)
20
+
21
+ - (void)messageReceivedForCallSid:(NSString *)callSid message:(TVOCallMessage *)callMessage {
22
+ NSArray *keys = self.callMap.allKeys;
23
+ for (NSString *uuid in keys) {
24
+ TVOCall *call = self.callMap[uuid];
25
+ if ([call.sid isEqualToString:callSid]) {
26
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCall
27
+ body:@{kTwilioVoiceReactNativeEventKeyCall: [self callInfo:call],
28
+ kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventMessageReceived,
29
+ kTwilioVoiceReactNativeJSEventKeyCallMessageInfo: [self callMessageInfo:callMessage]}];
30
+ return;
31
+ }
32
+ }
33
+
34
+ keys = self.callInviteMap.allKeys;
35
+ for (NSString *uuid in keys) {
36
+ TVOCallInvite *callInvite = self.callInviteMap[uuid];
37
+ if ([callInvite.callSid isEqualToString:callSid]) {
38
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCallInvite
39
+ body:@{kTwilioVoiceReactNativeCallInviteEventKeyCallSid: callSid,
40
+ kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventMessageReceived,
41
+ kTwilioVoiceReactNativeJSEventKeyCallMessageInfo: [self callMessageInfo:callMessage]}];
42
+ return;
43
+ }
44
+ }
45
+
46
+ NSLog(@"No match call or call invite for %@", callSid);
47
+ }
48
+
49
+ - (void)messageSentForCallSid:(NSString *)callSid voiceEventSid:(NSString *)voiceEventSid {
50
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCallMessage
51
+ body:@{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventMessageSent,
52
+ kTwilioVoiceReactNativeVoiceEventSid: voiceEventSid}];
53
+ }
54
+
55
+ - (void)messageFailedForCallSid:(NSString *)callSid voiceEventSid:(NSString *)voiceEventSid error:(NSError *)error {
56
+ // NOTE(mhuynh): We need a delay here to prevent race conditions where some errors are synchronously handled
57
+ // by the C++ SDK. For those synchronously handled errors, the JS layer is not given enough time to construct
58
+ // and bind event listeners for this event.
59
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
60
+ [self sendEventWithName:kTwilioVoiceReactNativeScopeCallMessage
61
+ body:@{kTwilioVoiceReactNativeVoiceEventType: kTwilioVoiceReactNativeCallEventMessageFailure,
62
+ kTwilioVoiceReactNativeVoiceEventSid: voiceEventSid,
63
+ kTwilioVoiceReactNativeVoiceErrorKeyError: @{kTwilioVoiceReactNativeVoiceErrorKeyCode: @(error.code),
64
+ kTwilioVoiceReactNativeVoiceErrorKeyMessage: [error localizedDescription]}}];
65
+ });
66
+ }
67
+
68
+ #pragma mark - Utility
69
+
70
+ - (NSDictionary *)callMessageInfo:(TVOCallMessage *)callMessage {
71
+ NSDictionary *callMessageInfoObject = @{
72
+ kTwilioVoiceReactNativeVoiceEventSid: callMessage.voiceEventSid,
73
+ kTwilioVoiceReactNativeCallMessageContent: callMessage.content,
74
+ kTwilioVoiceReactNativeCallMessageContentType: callMessage.contentType,
75
+ kTwilioVoiceReactNativeCallMessageMessageType: callMessage.messageType
76
+ };
77
+
78
+ return callMessageInfoObject;
79
+ }
80
+
81
+ @end
@@ -0,0 +1,74 @@
1
+ //
2
+ // TwilioVoiceReactNative.h
3
+ // TwilioVoiceReactNative
4
+ //
5
+ // Copyright © 2022 Twilio, Inc. All rights reserved.
6
+ //
7
+
8
+ #import <AVFoundation/AVFoundation.h>
9
+
10
+ #import <React/RCTBridgeModule.h>
11
+ #import <React/RCTEventEmitter.h>
12
+
13
+ @class CXCallController;
14
+ @class CXProvider;
15
+ @class TVOCall;
16
+ @class TVOCallInvite;
17
+ @class TVOCancelledCallInvite;
18
+ @class TVODefaultAudioDevice;
19
+
20
+ FOUNDATION_EXPORT NSString * const kTwilioVoiceReactNativeEventKeyCall;
21
+ FOUNDATION_EXPORT NSString * const kTwilioVoiceReactNativeEventKeyCallInvite;
22
+ FOUNDATION_EXPORT NSString * const kTwilioVoiceReactNativeEventKeyCancelledCallInvite;
23
+
24
+ @interface TwilioVoiceReactNative : RCTEventEmitter <RCTBridgeModule>
25
+
26
+ @property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, TVOCall *> *callMap;
27
+ @property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, NSString *> *callConnectMap;
28
+ @property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, TVOCallInvite *> *callInviteMap;
29
+ @property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, TVOCancelledCallInvite *> *cancelledCallInviteMap;
30
+
31
+ @property (nonatomic, strong) CXProvider *callKitProvider;
32
+ @property (nonatomic, strong) CXCallController *callKitCallController;
33
+
34
+ @property (nonatomic, copy) NSString *accessToken;
35
+ @property (nonatomic, copy) NSDictionary *twimlParams;
36
+ @property (nonatomic, strong) void(^callKitCompletionCallback)(BOOL);
37
+ @property (nonatomic, strong) RCTPromiseResolveBlock callPromiseResolver;
38
+
39
+ // Indicates if the disconnect is triggered from app UI, instead of the system Call UI
40
+ @property (nonatomic, assign) BOOL userInitiatedDisconnect;
41
+
42
+ @property (nonatomic, strong) AVAudioPlayer *ringbackPlayer;
43
+
44
+ + (TVODefaultAudioDevice *)twilioAudioDevice;
45
+
46
+ @end
47
+
48
+ @interface TwilioVoiceReactNative (EventEmitter)
49
+
50
+ // Override so we can check the event observer before emitting events
51
+ - (void)sendEventWithName:(NSString *)eventName body:(id)body;
52
+
53
+ @end
54
+
55
+ @interface TwilioVoiceReactNative (CallKit)
56
+
57
+ - (void)initializeCallKit;
58
+ - (void)initializeCallKitWithConfiguration:(NSDictionary *)configuration;
59
+ - (void)makeCallWithAccessToken:(NSString *)accessToken
60
+ params:(NSDictionary *)params
61
+ contactHandle:(NSString *)contactHandle;
62
+ - (void)reportNewIncomingCall:(TVOCallInvite *)callInvite;
63
+ - (void)endCallWithUuid:(NSUUID *)uuid;
64
+ /* Initiate the answering from the app UI */
65
+ - (void)answerCallInvite:(NSUUID *)uuid
66
+ completion:(void(^)(BOOL success))completionHandler;
67
+ - (void)updateCall:(NSString *)uuid callerHandle:(NSString *)handle;
68
+
69
+ /* Utility */
70
+ - (NSDictionary *)callInfo:(TVOCall *)call;
71
+ - (NSDictionary *)callInviteInfo:(TVOCallInvite *)callInvite;
72
+ - (NSDictionary *)cancelledCallInviteInfo:(TVOCancelledCallInvite *)cancelledCallInvite;
73
+
74
+ @end