@stream-io/video-react-native-sdk 1.31.1-beta.0 → 1.31.1

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 (217) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/android/src/main/AndroidManifest.xml +1 -8
  3. package/android/src/main/AndroidManifestNew.xml +0 -11
  4. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +5 -42
  5. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +6 -70
  6. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +4 -6
  7. package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +95 -0
  8. package/dist/commonjs/components/Participant/ParticipantView/ParticipantLabel.js +2 -6
  9. package/dist/commonjs/components/Participant/ParticipantView/ParticipantLabel.js.map +1 -1
  10. package/dist/commonjs/hooks/push/index.js +2 -0
  11. package/dist/commonjs/hooks/push/index.js.map +1 -1
  12. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +160 -0
  13. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  14. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  15. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  16. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +67 -0
  17. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +1 -0
  18. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +97 -64
  19. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  20. package/dist/commonjs/index.js +0 -1
  21. package/dist/commonjs/index.js.map +1 -1
  22. package/dist/commonjs/modules/call-manager/CallManager.js +0 -26
  23. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  24. package/dist/commonjs/providers/StreamCall/index.js +6 -6
  25. package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
  26. package/dist/commonjs/utils/StreamVideoRN/index.js +21 -35
  27. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  28. package/dist/commonjs/utils/internal/registerSDKGlobals.js +3 -53
  29. package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
  30. package/dist/commonjs/utils/push/android.js +202 -135
  31. package/dist/commonjs/utils/push/android.js.map +1 -1
  32. package/dist/commonjs/utils/push/internal/ios.js +34 -17
  33. package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
  34. package/dist/commonjs/utils/push/internal/rxSubjects.js +45 -1
  35. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
  36. package/dist/commonjs/utils/push/internal/utils.js +53 -71
  37. package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
  38. package/dist/commonjs/utils/push/ios.js.map +1 -1
  39. package/dist/commonjs/utils/push/libs/callkeep.js +17 -0
  40. package/dist/commonjs/utils/push/libs/callkeep.js.map +1 -0
  41. package/dist/commonjs/utils/push/libs/index.js +19 -8
  42. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  43. package/dist/commonjs/utils/push/libs/notifee/index.js +19 -0
  44. package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
  45. package/dist/commonjs/utils/push/libs/voipPushNotification.js +17 -0
  46. package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +1 -0
  47. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +205 -0
  48. package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +1 -0
  49. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +6 -7
  50. package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
  51. package/dist/commonjs/version.js +1 -1
  52. package/dist/commonjs/version.js.map +1 -1
  53. package/dist/module/components/Participant/ParticipantView/ParticipantLabel.js +2 -6
  54. package/dist/module/components/Participant/ParticipantView/ParticipantLabel.js.map +1 -1
  55. package/dist/module/hooks/push/index.js +2 -0
  56. package/dist/module/hooks/push/index.js.map +1 -1
  57. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +153 -0
  58. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
  59. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
  60. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  61. package/dist/module/hooks/push/useProcessPushCallEffect.js +60 -0
  62. package/dist/module/hooks/push/useProcessPushCallEffect.js.map +1 -0
  63. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +99 -66
  64. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  65. package/dist/module/index.js +0 -1
  66. package/dist/module/index.js.map +1 -1
  67. package/dist/module/modules/call-manager/CallManager.js +0 -26
  68. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  69. package/dist/module/providers/StreamCall/index.js +6 -6
  70. package/dist/module/providers/StreamCall/index.js.map +1 -1
  71. package/dist/module/utils/StreamVideoRN/index.js +21 -35
  72. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  73. package/dist/module/utils/internal/registerSDKGlobals.js +3 -53
  74. package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
  75. package/dist/module/utils/push/android.js +204 -137
  76. package/dist/module/utils/push/android.js.map +1 -1
  77. package/dist/module/utils/push/internal/ios.js +34 -17
  78. package/dist/module/utils/push/internal/ios.js.map +1 -1
  79. package/dist/module/utils/push/internal/rxSubjects.js +44 -0
  80. package/dist/module/utils/push/internal/rxSubjects.js.map +1 -1
  81. package/dist/module/utils/push/internal/utils.js +50 -67
  82. package/dist/module/utils/push/internal/utils.js.map +1 -1
  83. package/dist/module/utils/push/ios.js.map +1 -1
  84. package/dist/module/utils/push/libs/callkeep.js +11 -0
  85. package/dist/module/utils/push/libs/callkeep.js.map +1 -0
  86. package/dist/module/utils/push/libs/index.js +2 -1
  87. package/dist/module/utils/push/libs/index.js.map +1 -1
  88. package/dist/module/utils/push/libs/notifee/index.js +18 -0
  89. package/dist/module/utils/push/libs/notifee/index.js.map +1 -1
  90. package/dist/module/utils/push/libs/voipPushNotification.js +11 -0
  91. package/dist/module/utils/push/libs/voipPushNotification.js.map +1 -0
  92. package/dist/module/utils/push/setupIosCallKeepEvents.js +199 -0
  93. package/dist/module/utils/push/setupIosCallKeepEvents.js.map +1 -0
  94. package/dist/module/utils/push/setupIosVoipPushEvents.js +6 -7
  95. package/dist/module/utils/push/setupIosVoipPushEvents.js.map +1 -1
  96. package/dist/module/version.js +1 -1
  97. package/dist/module/version.js.map +1 -1
  98. package/dist/typescript/components/Participant/ParticipantView/ParticipantLabel.d.ts.map +1 -1
  99. package/dist/typescript/hooks/push/index.d.ts.map +1 -1
  100. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +5 -0
  101. package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +1 -0
  102. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  103. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts +8 -0
  104. package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts.map +1 -0
  105. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  106. package/dist/typescript/index.d.ts +0 -1
  107. package/dist/typescript/index.d.ts.map +1 -1
  108. package/dist/typescript/modules/call-manager/CallManager.d.ts +0 -5
  109. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  110. package/dist/typescript/utils/StreamVideoRN/index.d.ts +2 -22
  111. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  112. package/dist/typescript/utils/StreamVideoRN/types.d.ts +25 -59
  113. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  114. package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
  115. package/dist/typescript/utils/push/android.d.ts +2 -1
  116. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  117. package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
  118. package/dist/typescript/utils/push/internal/rxSubjects.d.ts +33 -0
  119. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
  120. package/dist/typescript/utils/push/internal/utils.d.ts +8 -14
  121. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
  122. package/dist/typescript/utils/push/ios.d.ts +2 -1
  123. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  124. package/dist/typescript/utils/push/libs/callkeep.d.ts +3 -0
  125. package/dist/typescript/utils/push/libs/callkeep.d.ts.map +1 -0
  126. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts +2 -16
  127. package/dist/typescript/utils/push/libs/firebaseMessaging/index.d.ts.map +1 -1
  128. package/dist/typescript/utils/push/libs/index.d.ts +2 -1
  129. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  130. package/dist/typescript/utils/push/libs/notifee/index.d.ts +1 -0
  131. package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
  132. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +3 -0
  133. package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +1 -0
  134. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +6 -0
  135. package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +1 -0
  136. package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
  137. package/dist/typescript/version.d.ts +1 -1
  138. package/dist/typescript/version.d.ts.map +1 -1
  139. package/expo-config-plugin/dist/withAndroidManifest.js +33 -1
  140. package/expo-config-plugin/dist/withAndroidPermissions.js +7 -2
  141. package/expo-config-plugin/dist/withAppDelegate.js +197 -19
  142. package/expo-config-plugin/dist/withMainActivity.js +1 -1
  143. package/expo-config-plugin/dist/withiOSInfoPlist.js +3 -2
  144. package/ios/StreamInCallManager.m +0 -2
  145. package/ios/StreamInCallManager.swift +7 -19
  146. package/ios/StreamVideoReactNative.h +4 -7
  147. package/ios/StreamVideoReactNative.m +82 -189
  148. package/package.json +16 -11
  149. package/src/components/Participant/ParticipantView/ParticipantLabel.tsx +2 -7
  150. package/src/hooks/push/index.ts +2 -0
  151. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +235 -0
  152. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +34 -21
  153. package/src/hooks/push/useProcessPushCallEffect.ts +108 -0
  154. package/src/hooks/useAndroidKeepCallAliveEffect.ts +120 -94
  155. package/src/index.ts +0 -1
  156. package/src/modules/call-manager/CallManager.ts +0 -36
  157. package/src/modules/call-manager/native-module.d.ts +0 -7
  158. package/src/providers/StreamCall/index.tsx +6 -6
  159. package/src/utils/StreamVideoRN/index.ts +30 -42
  160. package/src/utils/StreamVideoRN/types.ts +25 -61
  161. package/src/utils/internal/registerSDKGlobals.ts +4 -52
  162. package/src/utils/push/android.ts +311 -198
  163. package/src/utils/push/internal/ios.ts +44 -28
  164. package/src/utils/push/internal/rxSubjects.ts +61 -0
  165. package/src/utils/push/internal/utils.ts +64 -108
  166. package/src/utils/push/ios.ts +6 -1
  167. package/src/utils/push/libs/callkeep.ts +16 -0
  168. package/src/utils/push/libs/index.ts +2 -1
  169. package/src/utils/push/libs/notifee/index.ts +27 -0
  170. package/src/utils/push/libs/voipPushNotification.ts +17 -0
  171. package/src/utils/push/setupIosCallKeepEvents.ts +252 -0
  172. package/src/utils/push/setupIosVoipPushEvents.ts +7 -11
  173. package/src/version.ts +1 -1
  174. package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +0 -83
  175. package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +0 -149
  176. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +0 -144
  177. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  178. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +0 -68
  179. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +0 -1
  180. package/dist/commonjs/utils/internal/callingx/callingx.js +0 -150
  181. package/dist/commonjs/utils/internal/callingx/callingx.js.map +0 -1
  182. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +0 -48
  183. package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +0 -1
  184. package/dist/commonjs/utils/push/libs/callingx.js +0 -75
  185. package/dist/commonjs/utils/push/libs/callingx.js.map +0 -1
  186. package/dist/commonjs/utils/push/setupCallingExpEvents.js +0 -105
  187. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +0 -1
  188. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +0 -137
  189. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
  190. package/dist/module/utils/internal/callingx/audioSessionPromise.js +0 -61
  191. package/dist/module/utils/internal/callingx/audioSessionPromise.js.map +0 -1
  192. package/dist/module/utils/internal/callingx/callingx.js +0 -140
  193. package/dist/module/utils/internal/callingx/callingx.js.map +0 -1
  194. package/dist/module/utils/keepCallAliveHeadlessTask.js +0 -42
  195. package/dist/module/utils/keepCallAliveHeadlessTask.js.map +0 -1
  196. package/dist/module/utils/push/libs/callingx.js +0 -67
  197. package/dist/module/utils/push/libs/callingx.js.map +0 -1
  198. package/dist/module/utils/push/setupCallingExpEvents.js +0 -99
  199. package/dist/module/utils/push/setupCallingExpEvents.js.map +0 -1
  200. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +0 -5
  201. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +0 -1
  202. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +0 -16
  203. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +0 -1
  204. package/dist/typescript/utils/internal/callingx/callingx.d.ts +0 -18
  205. package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +0 -1
  206. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +0 -10
  207. package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +0 -1
  208. package/dist/typescript/utils/push/libs/callingx.d.ts +0 -9
  209. package/dist/typescript/utils/push/libs/callingx.d.ts.map +0 -1
  210. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +0 -8
  211. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +0 -1
  212. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +0 -189
  213. package/src/utils/internal/callingx/audioSessionPromise.ts +0 -65
  214. package/src/utils/internal/callingx/callingx.ts +0 -194
  215. package/src/utils/keepCallAliveHeadlessTask.ts +0 -54
  216. package/src/utils/push/libs/callingx.ts +0 -89
  217. package/src/utils/push/setupCallingExpEvents.ts +0 -135
@@ -0,0 +1,252 @@
1
+ import {
2
+ pushAcceptedIncomingCallCId$,
3
+ voipCallkeepAcceptedCallOnNativeDialerMap$,
4
+ voipCallkeepCallOnForegroundMap$,
5
+ voipPushNotificationCallCId$,
6
+ } from './internal/rxSubjects';
7
+ import { RxUtils, videoLoggerSystem } from '@stream-io/video-client';
8
+ import { getCallKeepLib, getVoipPushNotificationLib } from './libs';
9
+ import type { StreamVideoConfig } from '../StreamVideoRN/types';
10
+ import {
11
+ clearPushWSEventSubscriptions,
12
+ processCallFromPushInBackground,
13
+ } from './internal/utils';
14
+ import { AppState, NativeModules, Platform } from 'react-native';
15
+ import { RTCAudioSession } from '@stream-io/react-native-webrtc';
16
+ import { setPushLogoutCallback } from '../internal/pushLogoutCallback';
17
+
18
+ type PushConfig = NonNullable<StreamVideoConfig['push']>;
19
+
20
+ /**
21
+ * This hook is used to listen to callkeep events and do the necessary actions
22
+ */
23
+ export function setupIosCallKeepEvents(
24
+ pushConfig: NonNullable<StreamVideoConfig['push']>,
25
+ ) {
26
+ if (Platform.OS !== 'ios' || !pushConfig.ios.pushProviderName) {
27
+ return;
28
+ }
29
+ if (!pushConfig.android.incomingCallChannel) {
30
+ // TODO: remove this check and find a better way once we have telecom integration for android
31
+ videoLoggerSystem
32
+ .getLogger('setupIosCallKeepEvents')
33
+ .debug(
34
+ 'android incomingCallChannel is not defined, so skipping the setupIosCallKeepEvents',
35
+ );
36
+ return;
37
+ }
38
+ const logger = videoLoggerSystem.getLogger('setupIosCallKeepEvents');
39
+ const callkeep = getCallKeepLib();
40
+
41
+ async function getCallCid(callUUID: string): Promise<string | undefined> {
42
+ try {
43
+ const call_cid =
44
+ await NativeModules.StreamVideoReactNative.getIncomingCallCid(callUUID);
45
+ // in a case that voipPushNotificationCallCId$ is empty (this should not happen as voipPushNotificationCallCId$ is updated in push reception)]
46
+ // update it with this call_cid
47
+ const voipPushNotificationCallCId = RxUtils.getCurrentValue(
48
+ voipPushNotificationCallCId$,
49
+ );
50
+ if (!voipPushNotificationCallCId) {
51
+ logger.debug(
52
+ `voipPushNotificationCallCId$ is empty, updating it with the call_cid: ${call_cid} for callUUID: ${callUUID}`,
53
+ );
54
+ voipPushNotificationCallCId$.next(call_cid);
55
+ }
56
+ return call_cid;
57
+ } catch {
58
+ logger.debug(
59
+ `Error in getting call cid from native module for callUUID: ${callUUID} - probably the call was already processed, so ignoring this callkeep event`,
60
+ );
61
+ }
62
+ return undefined;
63
+ }
64
+
65
+ function answerCall(callUUID: string) {
66
+ getCallCid(callUUID).then((call_cid) => {
67
+ logger.debug(`answerCall event with call_cid: ${call_cid}`);
68
+ iosCallkeepAcceptCall(call_cid, callUUID);
69
+ });
70
+ }
71
+
72
+ function endCall(callUUID: string) {
73
+ getCallCid(callUUID).then((call_cid) => {
74
+ logger.debug(`endCall event with call_cid: ${call_cid}`);
75
+ iosCallkeepRejectCall(call_cid, callUUID, pushConfig!);
76
+ });
77
+ }
78
+
79
+ /**
80
+ * CallKeep / CallKit audio-session events -> WebRTC (iOS)
81
+ *
82
+ * iOS CallKit is the authority that *activates* and *deactivates* the underlying `AVAudioSession`
83
+ * when a call is answered/ended from the system UI (lock screen, Call UI, Bluetooth, etc).
84
+ *
85
+ * WebRTC on iOS wraps `AVAudioSession` with `RTCAudioSession` and its AudioDeviceModule relies on
86
+ * being notified of those lifecycle transitions to correctly start/stop audio I/O and keep its
87
+ * internal activation state consistent (e.g. activation count, playout/recording start).
88
+ *
89
+ * If these callbacks don’t reach WebRTC, answering via the native dialer UI can result in:
90
+ * - no microphone capture / one-way audio
91
+ * - silent playout until the app forces an audio reconfiguration
92
+ * - flaky audio routing (speaker/earpiece/Bluetooth) across subsequent calls
93
+ *
94
+ * We forward CallKeep’s `didActivateAudioSession` / `didDeactivateAudioSession` events to WebRTC’s
95
+ * `RTCAudioSession.audioSessionDidActivate()` / `audioSessionDidDeactivate()` methods.
96
+ */
97
+ function didActivateAudioSession() {
98
+ logger.debug('didActivateAudioSession');
99
+ RTCAudioSession.audioSessionDidActivate();
100
+ }
101
+
102
+ function didDeactivateAudioSession() {
103
+ logger.debug('didDeactivateAudioSession');
104
+ RTCAudioSession.audioSessionDidDeactivate();
105
+ }
106
+
107
+ function didDisplayIncomingCall(callUUID: string, payload: object) {
108
+ const voipPushNotification = getVoipPushNotificationLib();
109
+ // @ts-expect-error - call_cid is not part of RNCallKeepEventPayload
110
+ const call_cid = payload?.call_cid as string | undefined;
111
+ logger.debug(
112
+ `didDisplayIncomingCall event with callUUID: ${callUUID} call_cid: ${call_cid}`,
113
+ );
114
+ if (call_cid) {
115
+ if (AppState.currentState === 'background') {
116
+ processCallFromPushInBackground(
117
+ pushConfig!,
118
+ call_cid,
119
+ 'backgroundDelivered',
120
+ );
121
+ }
122
+ voipCallkeepCallOnForegroundMap$.next({
123
+ uuid: callUUID,
124
+ cid: call_cid,
125
+ });
126
+ }
127
+ voipPushNotification.onVoipNotificationCompleted(callUUID);
128
+ }
129
+
130
+ const { remove: removeAnswerCall } = callkeep.addEventListener(
131
+ 'answerCall',
132
+ ({ callUUID }) => {
133
+ answerCall(callUUID);
134
+ },
135
+ );
136
+ const { remove: removeEndCall } = callkeep.addEventListener(
137
+ 'endCall',
138
+ ({ callUUID }) => {
139
+ endCall(callUUID);
140
+ },
141
+ );
142
+
143
+ const { remove: removeDisplayIncomingCall } = callkeep.addEventListener(
144
+ 'didDisplayIncomingCall',
145
+ ({ callUUID, payload }) => {
146
+ didDisplayIncomingCall(callUUID, payload);
147
+ },
148
+ );
149
+
150
+ const { remove: removeDidActivateAudioSession } = callkeep.addEventListener(
151
+ 'didActivateAudioSession',
152
+ () => {
153
+ didActivateAudioSession();
154
+ },
155
+ );
156
+
157
+ const { remove: removeDidDeactivateAudioSession } = callkeep.addEventListener(
158
+ 'didDeactivateAudioSession',
159
+ () => {
160
+ didDeactivateAudioSession();
161
+ },
162
+ );
163
+
164
+ const { remove: removeDidLoadWithEvents } = callkeep.addEventListener(
165
+ 'didLoadWithEvents',
166
+ (events) => {
167
+ if (!events || !Array.isArray(events) || events.length < 1) {
168
+ return;
169
+ }
170
+
171
+ events.forEach((event) => {
172
+ const { name, data } = event;
173
+ if (name === 'RNCallKeepDidDisplayIncomingCall') {
174
+ didDisplayIncomingCall(data.callUUID, data.payload);
175
+ } else if (name === 'RNCallKeepPerformAnswerCallAction') {
176
+ answerCall(data.callUUID);
177
+ } else if (name === 'RNCallKeepPerformEndCallAction') {
178
+ endCall(data.callUUID);
179
+ } else if (name === 'RNCallKeepDidActivateAudioSession') {
180
+ didActivateAudioSession();
181
+ } else if (name === 'RNCallKeepDidDeactivateAudioSession') {
182
+ didDeactivateAudioSession();
183
+ }
184
+ });
185
+ },
186
+ );
187
+
188
+ setPushLogoutCallback(async () => {
189
+ removeAnswerCall();
190
+ removeEndCall();
191
+ removeDisplayIncomingCall();
192
+ removeDidActivateAudioSession();
193
+ removeDidDeactivateAudioSession();
194
+ removeDidLoadWithEvents();
195
+ });
196
+ }
197
+
198
+ const iosCallkeepAcceptCall = (
199
+ call_cid: string | undefined,
200
+ callUUIDFromCallkeep: string,
201
+ ) => {
202
+ if (!shouldProcessCallFromCallkeep(call_cid, callUUIDFromCallkeep)) {
203
+ return;
204
+ }
205
+ clearPushWSEventSubscriptions(call_cid);
206
+ // to call end callkeep later if ended in app and not through callkeep
207
+ voipCallkeepAcceptedCallOnNativeDialerMap$.next({
208
+ uuid: callUUIDFromCallkeep,
209
+ cid: call_cid,
210
+ });
211
+ // to process the call in the app
212
+ pushAcceptedIncomingCallCId$.next(call_cid);
213
+ // no need to keep these references anymore
214
+ voipCallkeepCallOnForegroundMap$.next(undefined);
215
+ };
216
+
217
+ const iosCallkeepRejectCall = async (
218
+ call_cid: string | undefined,
219
+ callUUIDFromCallkeep: string,
220
+ pushConfig: PushConfig,
221
+ ) => {
222
+ if (!shouldProcessCallFromCallkeep(call_cid, callUUIDFromCallkeep)) {
223
+ return;
224
+ }
225
+ clearPushWSEventSubscriptions(call_cid);
226
+ // remove the references if the call_cid matches
227
+ const voipPushNotificationCallCId = RxUtils.getCurrentValue(
228
+ voipPushNotificationCallCId$,
229
+ );
230
+ if (voipPushNotificationCallCId === call_cid) {
231
+ voipCallkeepAcceptedCallOnNativeDialerMap$.next(undefined);
232
+ voipCallkeepCallOnForegroundMap$.next(undefined);
233
+ voipPushNotificationCallCId$.next(undefined);
234
+ }
235
+
236
+ await processCallFromPushInBackground(pushConfig, call_cid, 'decline');
237
+ await NativeModules.StreamVideoReactNative?.removeIncomingCall(call_cid);
238
+ };
239
+
240
+ /**
241
+ * Helper function to determine if the answer/end call event from callkeep must be processed
242
+ * Just checks if we have a valid call_cid and acts as a type guard for call_cid
243
+ */
244
+ const shouldProcessCallFromCallkeep = (
245
+ call_cid: string | undefined,
246
+ callUUIDFromCallkeep: string,
247
+ ): call_cid is string => {
248
+ if (!call_cid || !callUUIDFromCallkeep) {
249
+ return false;
250
+ }
251
+ return true;
252
+ };
@@ -1,11 +1,10 @@
1
- // import { getVoipPushNotificationLib } from './libs';
1
+ import { getVoipPushNotificationLib } from './libs';
2
2
 
3
3
  import { Platform } from 'react-native';
4
4
  import { onVoipNotificationReceived } from './internal/ios';
5
5
  import { setPushLogoutCallback } from '../internal/pushLogoutCallback';
6
6
  import { StreamVideoConfig } from '../StreamVideoRN/types';
7
7
  import { videoLoggerSystem } from '@stream-io/video-client';
8
- import { getCallingxLib } from './libs';
9
8
 
10
9
  export function setupIosVoipPushEvents(
11
10
  pushConfig: NonNullable<StreamVideoConfig['push']>,
@@ -21,19 +20,16 @@ export function setupIosVoipPushEvents(
21
20
  );
22
21
  return;
23
22
  }
23
+ const voipPushNotification = getVoipPushNotificationLib();
24
24
 
25
- const callingx = getCallingxLib();
26
- const voipNotificationReceivedListener = callingx.addEventListener(
27
- 'voipNotificationReceived',
28
- (params) => {
29
- onVoipNotificationReceived(params, pushConfig);
30
- },
31
- );
32
-
25
+ logger.debug('notification event listener added');
26
+ voipPushNotification.addEventListener('notification', (notification) => {
27
+ onVoipNotificationReceived(notification, pushConfig);
28
+ });
33
29
  setPushLogoutCallback(async () => {
34
30
  videoLoggerSystem
35
31
  .getLogger('setPushLogoutCallback')
36
32
  .debug('notification event listener removed');
37
- voipNotificationReceivedListener.remove();
33
+ voipPushNotification.removeEventListener('notification');
38
34
  });
39
35
  }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.31.1-beta.0';
1
+ export const version = '1.31.1';
@@ -1,83 +0,0 @@
1
- package com.streamvideo.reactnative.keepalive
2
-
3
- import android.app.Notification
4
- import android.app.NotificationChannel
5
- import android.app.NotificationManager
6
- import android.app.PendingIntent
7
- import android.content.Context
8
- import android.content.Intent
9
- import android.content.pm.PackageManager
10
- import android.os.Build
11
- import androidx.core.app.NotificationCompat
12
-
13
- internal object KeepAliveNotification {
14
- private const val DEFAULT_CHANNEL_DESCRIPTION = "Stream call keep-alive"
15
-
16
- fun ensureChannel(
17
- context: Context,
18
- channelId: String,
19
- channelName: String
20
- ) {
21
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
22
- val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
23
- val existing = manager.getNotificationChannel(channelId)
24
- if (existing != null) return
25
-
26
- val channel = NotificationChannel(
27
- channelId,
28
- channelName,
29
- NotificationManager.IMPORTANCE_LOW
30
- ).apply {
31
- description = DEFAULT_CHANNEL_DESCRIPTION
32
- setShowBadge(false)
33
- }
34
- manager.createNotificationChannel(channel)
35
- }
36
-
37
- fun buildOngoingNotification(
38
- context: Context,
39
- channelId: String,
40
- title: String,
41
- body: String,
42
- smallIconName: String?
43
- ): Notification {
44
- val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
45
- val pendingIntentFlags =
46
- PendingIntent.FLAG_UPDATE_CURRENT or
47
- PendingIntent.FLAG_IMMUTABLE
48
- val contentIntent = if (launchIntent != null) {
49
- PendingIntent.getActivity(context, 0, launchIntent, pendingIntentFlags)
50
- } else {
51
- // Fallback: empty intent to avoid crash if launch activity is missing for some reason
52
- PendingIntent.getActivity(context, 0, Intent(), pendingIntentFlags)
53
- }
54
-
55
- val iconResId = resolveSmallIconResId(context, smallIconName)
56
- return NotificationCompat.Builder(context, channelId)
57
- .setContentTitle(title)
58
- .setContentText(body)
59
- .setOngoing(true)
60
- .setOnlyAlertOnce(true)
61
- .setCategory(NotificationCompat.CATEGORY_CALL)
62
- .setContentIntent(contentIntent)
63
- .setSmallIcon(iconResId)
64
- .build()
65
- }
66
-
67
- private fun resolveSmallIconResId(context: Context, smallIconName: String?): Int {
68
- val resources = context.resources
69
- val packageName = context.packageName
70
- if (!smallIconName.isNullOrBlank()) {
71
- val id = resources.getIdentifier(smallIconName, "drawable", packageName)
72
- if (id != 0) return id
73
- }
74
- // Default to the app icon
75
- return try {
76
- val appInfo = context.packageManager.getApplicationInfo(packageName, 0)
77
- appInfo.icon
78
- } catch (_: PackageManager.NameNotFoundException) {
79
- android.R.drawable.ic_dialog_info
80
- }
81
- }
82
- }
83
-
@@ -1,149 +0,0 @@
1
- package com.streamvideo.reactnative.keepalive
2
-
3
- import android.Manifest
4
- import android.content.Intent
5
- import android.content.pm.PackageManager
6
- import android.content.pm.ServiceInfo
7
- import android.os.Build
8
- import android.util.Log
9
- import androidx.annotation.RequiresApi
10
- import androidx.core.app.ServiceCompat
11
- import androidx.core.content.ContextCompat
12
- import com.facebook.react.HeadlessJsTaskService
13
- import com.facebook.react.bridge.Arguments
14
- import com.facebook.react.jstasks.HeadlessJsTaskConfig
15
-
16
- /**
17
- * Foreground service that runs a React Native HeadlessJS task to keep a call alive.
18
- *
19
- */
20
- class StreamCallKeepAliveHeadlessService : HeadlessJsTaskService() {
21
-
22
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
23
- val safeIntent = intent ?: Intent()
24
- val channelId = safeIntent.getStringExtra(EXTRA_CHANNEL_ID) ?: DEFAULT_CHANNEL_ID
25
- val channelName = safeIntent.getStringExtra(EXTRA_CHANNEL_NAME) ?: DEFAULT_CHANNEL_NAME
26
- val title = safeIntent.getStringExtra(EXTRA_TITLE) ?: DEFAULT_TITLE
27
- val body = safeIntent.getStringExtra(EXTRA_BODY) ?: DEFAULT_BODY
28
- val smallIconName = safeIntent.getStringExtra(EXTRA_SMALL_ICON_NAME)
29
-
30
- KeepAliveNotification.ensureChannel(this, channelId, channelName)
31
- val notification = KeepAliveNotification.buildOngoingNotification(
32
- context = this,
33
- channelId = channelId,
34
- title = title,
35
- body = body,
36
- smallIconName = smallIconName
37
- )
38
-
39
- startForegroundCompat(notification)
40
-
41
- // Ensure HeadlessJS task is started
42
- return super.onStartCommand(safeIntent, flags, startId)
43
- }
44
-
45
- override fun getTaskConfig(intent: Intent?): HeadlessJsTaskConfig? {
46
- val callCid = intent?.getStringExtra(EXTRA_CALL_CID) ?: return null
47
- val data = Arguments.createMap().apply {
48
- putString("callCid", callCid)
49
- }
50
- // We intentionally allow long-running work (the JS task can return a never-resolving Promise).
51
- return HeadlessJsTaskConfig(
52
- TASK_NAME,
53
- data,
54
- 0, // timeout (0 = no timeout)
55
- true // allowedInForeground
56
- )
57
- }
58
-
59
- override fun onDestroy() {
60
- super.onDestroy()
61
- stopForeground(STOP_FOREGROUND_REMOVE)
62
- }
63
-
64
- @RequiresApi(Build.VERSION_CODES.R)
65
- private fun computeForegroundServiceTypes(): Int {
66
- var types = ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
67
-
68
- val hasCameraPermission =
69
- ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
70
- if (hasCameraPermission) {
71
- types = types or ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
72
- }
73
-
74
- val hasMicrophonePermission =
75
- ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
76
- if (hasMicrophonePermission) {
77
- types = types or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
78
- }
79
-
80
- return types
81
- }
82
-
83
- private fun startForegroundCompat(notification: android.app.Notification) {
84
- try {
85
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
86
- val types =
87
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) computeForegroundServiceTypes()
88
- else ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
89
- startForeground(NOTIFICATION_ID, notification, types)
90
- } else {
91
- startForeground(NOTIFICATION_ID, notification)
92
- }
93
- } catch (e: Exception) {
94
- // Avoid crashing the app if the system rejects starting a foreground service (e.g.
95
- // background start restrictions, invalid notification/channel, or permission issues).
96
- Log.e(
97
- TAG,
98
- "startForegroundCompat: Failed to start foreground service: ${e.message}",
99
- e
100
- )
101
- }
102
- }
103
-
104
- companion object {
105
- private const val TAG = "StreamCallKeepAliveHeadlessService"
106
-
107
- const val TASK_NAME = "StreamVideoKeepCallAlive"
108
-
109
- const val EXTRA_CALL_CID = "callCid"
110
- const val EXTRA_CHANNEL_ID = "channelId"
111
- const val EXTRA_CHANNEL_NAME = "channelName"
112
- const val EXTRA_TITLE = "title"
113
- const val EXTRA_BODY = "body"
114
- const val EXTRA_SMALL_ICON_NAME = "smallIconName"
115
-
116
- private const val NOTIFICATION_ID = 6061
117
-
118
- private const val DEFAULT_CHANNEL_ID = "stream_call_foreground_service"
119
- private const val DEFAULT_CHANNEL_NAME = "Call in progress"
120
- private const val DEFAULT_TITLE = "Call in progress"
121
- private const val DEFAULT_BODY = "Tap to return to the call"
122
-
123
- fun buildStartIntent(
124
- context: android.content.Context,
125
- callCid: String,
126
- channelId: String,
127
- channelName: String,
128
- title: String,
129
- body: String,
130
- smallIconName: String?
131
- ): Intent {
132
- return Intent(context, StreamCallKeepAliveHeadlessService::class.java).apply {
133
- putExtra(EXTRA_CALL_CID, callCid)
134
- putExtra(EXTRA_CHANNEL_ID, channelId)
135
- putExtra(EXTRA_CHANNEL_NAME, channelName)
136
- putExtra(EXTRA_TITLE, title)
137
- putExtra(EXTRA_BODY, body)
138
- if (!smallIconName.isNullOrBlank()) {
139
- putExtra(EXTRA_SMALL_ICON_NAME, smallIconName)
140
- }
141
- }
142
- }
143
-
144
- fun buildStopIntent(context: android.content.Context): Intent {
145
- return Intent(context, StreamCallKeepAliveHeadlessService::class.java)
146
- }
147
- }
148
- }
149
-
@@ -1,144 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.useCallingExpWithCallingStateEffect = void 0;
7
- var _videoClient = require("@stream-io/video-client");
8
- var _videoReactBindings = require("@stream-io/video-react-bindings");
9
- var _react = require("react");
10
- var _operators = require("rxjs/operators");
11
- var _callingx = require("../../utils/internal/callingx/callingx");
12
- var _callingx2 = require("../../utils/push/libs/callingx");
13
- const logger = _videoClient.videoLoggerSystem.getLogger('callingx');
14
-
15
- /**
16
- * This hook is used to inform sync call state with CallKit/Telecom (i.e. start call, end call, mute/unmute call).
17
- */
18
- const useCallingExpWithCallingStateEffect = () => {
19
- const {
20
- useMicrophoneState,
21
- useParticipants,
22
- useCallMembers
23
- } = (0, _videoReactBindings.useCallStateHooks)();
24
- const activeCall = (0, _videoReactBindings.useCall)();
25
- const {
26
- isMute,
27
- microphone
28
- } = useMicrophoneState();
29
- const callMembers = useCallMembers();
30
- const participants = useParticipants();
31
- const activeCallCid = activeCall?.cid;
32
- const currentUserId = activeCall?.currentUserId;
33
- const isIncoming = activeCall?.ringing && !activeCall?.isCreatedByMe || false;
34
- const callDisplayName = (0, _react.useMemo)(() => (0, _callingx.getCallDisplayName)(callMembers, participants, currentUserId), [callMembers, participants, currentUserId]);
35
- (0, _react.useEffect)(() => {
36
- const callingx = (0, _callingx2.getCallingxLibIfAvailable)();
37
- if (!callingx?.isSetup || !activeCall) {
38
- return;
39
- }
40
- // need to capture RINGING -> Joining -> Joined state change for the first time
41
- // and inform callingx that the call is active
42
- const shouldMakeCallActive = call => {
43
- // only for outgoing calls or non-ringing ongoing calls in callingx
44
- // Note: incoming calls are handled by callingx pending states instead
45
- return call.ringing && call.isCreatedByMe || !call.ringing && callingx.isOngoingCallsEnabled;
46
- };
47
- const subscription = activeCall.state.callingState$.pipe((0, _operators.filter)(callingState => shouldMakeCallActive(activeCall) && callingState === _videoClient.CallingState.JOINED && callingx.isCallTracked(activeCall.cid)), (0, _operators.take)(1) // only need to capture the first joined state for outgoing calls
48
- // then subscription completes and is automatically unsubscribed
49
- ).subscribe(() => {
50
- callingx.setCurrentCallActive(activeCall.cid);
51
- });
52
- return () => {
53
- subscription.unsubscribe();
54
- };
55
- }, [activeCall]);
56
- (0, _react.useEffect)(() => {
57
- return () => {
58
- const callingx = (0, _callingx2.getCallingxLibIfAvailable)();
59
- if (!callingx?.isSetup || !activeCallCid) {
60
- return;
61
- }
62
- const isCallTracked = callingx.isCallTracked(activeCallCid);
63
- if (!isCallTracked) {
64
- logger.debug(`useCallingExpWithCallingStateEffect:No active call cid to end in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked}`);
65
- return;
66
- }
67
- //if incoming stream call was unmounted, we need to end the call in CallKit/Telecom
68
- logger.debug(`useCallingExpWithCallingStateEffect: Ending call in callingx: ${activeCallCid}`);
69
- callingx.endCallWithReason(activeCallCid, 'local').catch(error => {
70
- logger.error(`useCallingExpWithCallingStateEffect: Error ending call in callingx: ${activeCallCid}`, error);
71
- });
72
- };
73
- }, [activeCallCid]);
74
- (0, _react.useEffect)(() => {
75
- const callingx = (0, _callingx2.getCallingxLibIfAvailable)();
76
- if (!callingx?.isSetup || !activeCallCid) {
77
- return;
78
- }
79
- const isCallTracked = callingx.isCallTracked(activeCallCid);
80
- if (!isCallTracked) {
81
- logger.debug(`useCallingExpWithCallingStateEffect:No active call cid to update callingx: ${activeCallCid} isCallTracked: ${isCallTracked}`);
82
- return;
83
- }
84
- callingx.updateDisplay(activeCallCid, activeCallCid, callDisplayName, isIncoming);
85
- }, [activeCallCid, callDisplayName, isIncoming]);
86
-
87
- // Sync microphone mute state from app → CallKit
88
- (0, _react.useEffect)(() => {
89
- const callingx = (0, _callingx2.getCallingxLibIfAvailable)();
90
- if (!callingx?.isSetup || !activeCallCid) {
91
- return;
92
- }
93
- const isCallTracked = callingx.isCallTracked(activeCallCid);
94
- if (!isCallTracked) {
95
- logger.debug(`useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked}`);
96
- return;
97
- }
98
- callingx.setMutedCall(activeCallCid, isMute);
99
- }, [activeCallCid, isMute]);
100
-
101
- // Sync mute state from CallKit → app (only for system-initiated mute actions)
102
- (0, _react.useEffect)(() => {
103
- const callingx = (0, _callingx2.getCallingxLibIfAvailable)();
104
- if (!callingx?.isSetup || !activeCallCid) {
105
- logger.debug(`useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} callingx isSetup: ${callingx?.isSetup}`);
106
- return;
107
- }
108
-
109
- // Listen to mic toggle events from CallKit/Telecom and update stream call microphone state.
110
- // Only system-initiated mute actions (e.g. user tapped mute on the native CallKit UI)
111
- // are sent here — app-initiated actions are filtered out on the native side to prevent
112
- // the feedback loop: app mutes mic → setMutedCall → CallKit delegate → event to JS → loop.
113
- const subscription = callingx.addEventListener('didPerformSetMutedCallAction', async event => {
114
- const {
115
- callId,
116
- muted
117
- } = event;
118
- const isCallTracked = callingx.isCallTracked(activeCallCid);
119
- if (!isCallTracked || callId !== activeCallCid) {
120
- logger.debug(`useCallingExpWithCallingStateEffect: No active call cid to set muted in calling exp: ${activeCallCid} isCallTracked: ${isCallTracked} callId: ${callId}`);
121
- return;
122
- }
123
- const isCurrentlyMuted = microphone.state.status === 'disabled';
124
- if (isCurrentlyMuted === muted) {
125
- logger.debug(`useCallingExpWithCallingStateEffect: Mic toggle is already in the desired state: ${muted} for call: ${activeCallCid}`);
126
- return;
127
- }
128
- try {
129
- if (muted) {
130
- await microphone.disable();
131
- } else {
132
- await microphone.enable();
133
- }
134
- } catch (error) {
135
- logger.error(`useCallingExpWithCallingStateEffect: Error toggling mic in calling exp: ${activeCallCid}`, error);
136
- }
137
- });
138
- return () => {
139
- subscription.remove();
140
- };
141
- }, [activeCallCid, microphone]);
142
- };
143
- exports.useCallingExpWithCallingStateEffect = useCallingExpWithCallingStateEffect;
144
- //# sourceMappingURL=useCallingExpWithCallingStateEffect.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_videoClient","require","_videoReactBindings","_react","_operators","_callingx","_callingx2","logger","videoLoggerSystem","getLogger","useCallingExpWithCallingStateEffect","useMicrophoneState","useParticipants","useCallMembers","useCallStateHooks","activeCall","useCall","isMute","microphone","callMembers","participants","activeCallCid","cid","currentUserId","isIncoming","ringing","isCreatedByMe","callDisplayName","useMemo","getCallDisplayName","useEffect","callingx","getCallingxLibIfAvailable","isSetup","shouldMakeCallActive","call","isOngoingCallsEnabled","subscription","state","callingState$","pipe","filter","callingState","CallingState","JOINED","isCallTracked","take","subscribe","setCurrentCallActive","unsubscribe","debug","endCallWithReason","catch","error","updateDisplay","setMutedCall","addEventListener","event","callId","muted","isCurrentlyMuted","status","disable","enable","remove","exports"],"sourceRoot":"../../../../src","sources":["hooks/push/useCallingExpWithCallingStateEffect.ts"],"mappings":"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","ignoreList":[]}