@voltkit-rtc/react-native 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1606 -2
  4. package/android/build.gradle +70 -0
  5. package/android/consumer-rules.pro +21 -0
  6. package/android/src/main/AndroidManifest.xml +25 -0
  7. package/android/src/main/java/com/voltkit/rtc/reactnative/AppVisibility.kt +67 -0
  8. package/android/src/main/java/com/voltkit/rtc/reactnative/AudioDevices.kt +67 -0
  9. package/android/src/main/java/com/voltkit/rtc/reactnative/AudioRouter.kt +487 -0
  10. package/android/src/main/java/com/voltkit/rtc/reactnative/CallServiceTypes.kt +120 -0
  11. package/android/src/main/java/com/voltkit/rtc/reactnative/NativeTimers.kt +106 -0
  12. package/android/src/main/java/com/voltkit/rtc/reactnative/NetworkWatch.kt +120 -0
  13. package/android/src/main/java/com/voltkit/rtc/reactnative/OutputChoice.kt +65 -0
  14. package/android/src/main/java/com/voltkit/rtc/reactnative/RtcConfig.kt +83 -0
  15. package/android/src/main/java/com/voltkit/rtc/reactnative/ScoLink.kt +61 -0
  16. package/android/src/main/java/com/voltkit/rtc/reactnative/VoltkitCallService.kt +287 -0
  17. package/android/src/main/java/com/voltkit/rtc/reactnative/VoltkitRtcInitProvider.kt +215 -0
  18. package/android/src/main/java/com/voltkit/rtc/reactnative/VoltkitRtcModule.kt +313 -0
  19. package/android/src/main/java/com/voltkit/rtc/reactnative/VoltkitRtcPackage.kt +30 -0
  20. package/android/src/main/res/drawable/voltkit_rtc_default_call_icon.xml +15 -0
  21. package/android/src/main/res/raw/voltkit_rtc_keep.xml +7 -0
  22. package/app.plugin.js +17 -0
  23. package/lib/commonjs/audio.js +215 -0
  24. package/lib/commonjs/audio.js.map +1 -0
  25. package/lib/commonjs/components.js +207 -0
  26. package/lib/commonjs/components.js.map +1 -0
  27. package/lib/commonjs/create-client.js +47 -0
  28. package/lib/commonjs/create-client.js.map +1 -0
  29. package/lib/commonjs/errors.js +99 -0
  30. package/lib/commonjs/errors.js.map +1 -0
  31. package/lib/commonjs/globals.js +61 -0
  32. package/lib/commonjs/globals.js.map +1 -0
  33. package/lib/commonjs/index.js +234 -0
  34. package/lib/commonjs/index.js.map +1 -0
  35. package/lib/commonjs/local-media.js +392 -0
  36. package/lib/commonjs/local-media.js.map +1 -0
  37. package/lib/commonjs/native-session.js +314 -0
  38. package/lib/commonjs/native-session.js.map +1 -0
  39. package/lib/commonjs/native.js +99 -0
  40. package/lib/commonjs/native.js.map +1 -0
  41. package/lib/commonjs/package.json +1 -0
  42. package/lib/commonjs/permissions.js +166 -0
  43. package/lib/commonjs/permissions.js.map +1 -0
  44. package/lib/commonjs/platform/android.js +126 -0
  45. package/lib/commonjs/platform/android.js.map +1 -0
  46. package/lib/commonjs/platform/common.js +138 -0
  47. package/lib/commonjs/platform/common.js.map +1 -0
  48. package/lib/commonjs/platform/devices.js +151 -0
  49. package/lib/commonjs/platform/devices.js.map +1 -0
  50. package/lib/commonjs/platform/index.js +35 -0
  51. package/lib/commonjs/platform/index.js.map +1 -0
  52. package/lib/commonjs/platform/ios.js +54 -0
  53. package/lib/commonjs/platform/ios.js.map +1 -0
  54. package/lib/commonjs/platform/streams.js +273 -0
  55. package/lib/commonjs/platform/streams.js.map +1 -0
  56. package/lib/commonjs/platform/timers.js +71 -0
  57. package/lib/commonjs/platform/timers.js.map +1 -0
  58. package/lib/commonjs/platform/visibility.js +60 -0
  59. package/lib/commonjs/platform/visibility.js.map +1 -0
  60. package/lib/commonjs/preflight.js +77 -0
  61. package/lib/commonjs/preflight.js.map +1 -0
  62. package/lib/commonjs/provider.js +73 -0
  63. package/lib/commonjs/provider.js.map +1 -0
  64. package/lib/commonjs/specs/NativeVoltkitRtc.js +29 -0
  65. package/lib/commonjs/specs/NativeVoltkitRtc.js.map +1 -0
  66. package/lib/module/audio.js +207 -0
  67. package/lib/module/audio.js.map +1 -0
  68. package/lib/module/components.js +200 -0
  69. package/lib/module/components.js.map +1 -0
  70. package/lib/module/create-client.js +42 -0
  71. package/lib/module/create-client.js.map +1 -0
  72. package/lib/module/errors.js +87 -0
  73. package/lib/module/errors.js.map +1 -0
  74. package/lib/module/globals.js +53 -0
  75. package/lib/module/globals.js.map +1 -0
  76. package/lib/module/index.js +33 -0
  77. package/lib/module/index.js.map +1 -0
  78. package/lib/module/local-media.js +387 -0
  79. package/lib/module/local-media.js.map +1 -0
  80. package/lib/module/native-session.js +309 -0
  81. package/lib/module/native-session.js.map +1 -0
  82. package/lib/module/native.js +87 -0
  83. package/lib/module/native.js.map +1 -0
  84. package/lib/module/package.json +1 -0
  85. package/lib/module/permissions.js +160 -0
  86. package/lib/module/permissions.js.map +1 -0
  87. package/lib/module/platform/android.js +122 -0
  88. package/lib/module/platform/android.js.map +1 -0
  89. package/lib/module/platform/common.js +128 -0
  90. package/lib/module/platform/common.js.map +1 -0
  91. package/lib/module/platform/devices.js +142 -0
  92. package/lib/module/platform/devices.js.map +1 -0
  93. package/lib/module/platform/index.js +24 -0
  94. package/lib/module/platform/index.js.map +1 -0
  95. package/lib/module/platform/ios.js +49 -0
  96. package/lib/module/platform/ios.js.map +1 -0
  97. package/lib/module/platform/streams.js +268 -0
  98. package/lib/module/platform/streams.js.map +1 -0
  99. package/lib/module/platform/timers.js +67 -0
  100. package/lib/module/platform/timers.js.map +1 -0
  101. package/lib/module/platform/visibility.js +54 -0
  102. package/lib/module/platform/visibility.js.map +1 -0
  103. package/lib/module/preflight.js +72 -0
  104. package/lib/module/preflight.js.map +1 -0
  105. package/lib/module/provider.js +68 -0
  106. package/lib/module/provider.js.map +1 -0
  107. package/lib/module/specs/NativeVoltkitRtc.js +37 -0
  108. package/lib/module/specs/NativeVoltkitRtc.js.map +1 -0
  109. package/lib/typescript/commonjs/audio.d.ts +58 -0
  110. package/lib/typescript/commonjs/audio.d.ts.map +1 -0
  111. package/lib/typescript/commonjs/components.d.ts +58 -0
  112. package/lib/typescript/commonjs/components.d.ts.map +1 -0
  113. package/lib/typescript/commonjs/create-client.d.ts +35 -0
  114. package/lib/typescript/commonjs/create-client.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/errors.d.ts +34 -0
  116. package/lib/typescript/commonjs/errors.d.ts.map +1 -0
  117. package/lib/typescript/commonjs/globals.d.ts +16 -0
  118. package/lib/typescript/commonjs/globals.d.ts.map +1 -0
  119. package/lib/typescript/commonjs/index.d.ts +24 -0
  120. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/local-media.d.ts +86 -0
  122. package/lib/typescript/commonjs/local-media.d.ts.map +1 -0
  123. package/lib/typescript/commonjs/native-session.d.ts +38 -0
  124. package/lib/typescript/commonjs/native-session.d.ts.map +1 -0
  125. package/lib/typescript/commonjs/native.d.ts +18 -0
  126. package/lib/typescript/commonjs/native.d.ts.map +1 -0
  127. package/lib/typescript/commonjs/package.json +1 -0
  128. package/lib/typescript/commonjs/permissions.d.ts +30 -0
  129. package/lib/typescript/commonjs/permissions.d.ts.map +1 -0
  130. package/lib/typescript/commonjs/platform/android.d.ts +4 -0
  131. package/lib/typescript/commonjs/platform/android.d.ts.map +1 -0
  132. package/lib/typescript/commonjs/platform/common.d.ts +101 -0
  133. package/lib/typescript/commonjs/platform/common.d.ts.map +1 -0
  134. package/lib/typescript/commonjs/platform/devices.d.ts +42 -0
  135. package/lib/typescript/commonjs/platform/devices.d.ts.map +1 -0
  136. package/lib/typescript/commonjs/platform/index.d.ts +6 -0
  137. package/lib/typescript/commonjs/platform/index.d.ts.map +1 -0
  138. package/lib/typescript/commonjs/platform/ios.d.ts +4 -0
  139. package/lib/typescript/commonjs/platform/ios.d.ts.map +1 -0
  140. package/lib/typescript/commonjs/platform/streams.d.ts +82 -0
  141. package/lib/typescript/commonjs/platform/streams.d.ts.map +1 -0
  142. package/lib/typescript/commonjs/platform/timers.d.ts +19 -0
  143. package/lib/typescript/commonjs/platform/timers.d.ts.map +1 -0
  144. package/lib/typescript/commonjs/platform/visibility.d.ts +11 -0
  145. package/lib/typescript/commonjs/platform/visibility.d.ts.map +1 -0
  146. package/lib/typescript/commonjs/preflight.d.ts +19 -0
  147. package/lib/typescript/commonjs/preflight.d.ts.map +1 -0
  148. package/lib/typescript/commonjs/provider.d.ts +35 -0
  149. package/lib/typescript/commonjs/provider.d.ts.map +1 -0
  150. package/lib/typescript/commonjs/specs/NativeVoltkitRtc.d.ts +157 -0
  151. package/lib/typescript/commonjs/specs/NativeVoltkitRtc.d.ts.map +1 -0
  152. package/lib/typescript/module/audio.d.ts +58 -0
  153. package/lib/typescript/module/audio.d.ts.map +1 -0
  154. package/lib/typescript/module/components.d.ts +58 -0
  155. package/lib/typescript/module/components.d.ts.map +1 -0
  156. package/lib/typescript/module/create-client.d.ts +35 -0
  157. package/lib/typescript/module/create-client.d.ts.map +1 -0
  158. package/lib/typescript/module/errors.d.ts +34 -0
  159. package/lib/typescript/module/errors.d.ts.map +1 -0
  160. package/lib/typescript/module/globals.d.ts +16 -0
  161. package/lib/typescript/module/globals.d.ts.map +1 -0
  162. package/lib/typescript/module/index.d.ts +24 -0
  163. package/lib/typescript/module/index.d.ts.map +1 -0
  164. package/lib/typescript/module/local-media.d.ts +86 -0
  165. package/lib/typescript/module/local-media.d.ts.map +1 -0
  166. package/lib/typescript/module/native-session.d.ts +38 -0
  167. package/lib/typescript/module/native-session.d.ts.map +1 -0
  168. package/lib/typescript/module/native.d.ts +18 -0
  169. package/lib/typescript/module/native.d.ts.map +1 -0
  170. package/lib/typescript/module/package.json +1 -0
  171. package/lib/typescript/module/permissions.d.ts +30 -0
  172. package/lib/typescript/module/permissions.d.ts.map +1 -0
  173. package/lib/typescript/module/platform/android.d.ts +4 -0
  174. package/lib/typescript/module/platform/android.d.ts.map +1 -0
  175. package/lib/typescript/module/platform/common.d.ts +101 -0
  176. package/lib/typescript/module/platform/common.d.ts.map +1 -0
  177. package/lib/typescript/module/platform/devices.d.ts +42 -0
  178. package/lib/typescript/module/platform/devices.d.ts.map +1 -0
  179. package/lib/typescript/module/platform/index.d.ts +6 -0
  180. package/lib/typescript/module/platform/index.d.ts.map +1 -0
  181. package/lib/typescript/module/platform/ios.d.ts +4 -0
  182. package/lib/typescript/module/platform/ios.d.ts.map +1 -0
  183. package/lib/typescript/module/platform/streams.d.ts +82 -0
  184. package/lib/typescript/module/platform/streams.d.ts.map +1 -0
  185. package/lib/typescript/module/platform/timers.d.ts +19 -0
  186. package/lib/typescript/module/platform/timers.d.ts.map +1 -0
  187. package/lib/typescript/module/platform/visibility.d.ts +11 -0
  188. package/lib/typescript/module/platform/visibility.d.ts.map +1 -0
  189. package/lib/typescript/module/preflight.d.ts +19 -0
  190. package/lib/typescript/module/preflight.d.ts.map +1 -0
  191. package/lib/typescript/module/provider.d.ts +35 -0
  192. package/lib/typescript/module/provider.d.ts.map +1 -0
  193. package/lib/typescript/module/specs/NativeVoltkitRtc.d.ts +157 -0
  194. package/lib/typescript/module/specs/NativeVoltkitRtc.d.ts.map +1 -0
  195. package/package.json +140 -4
  196. package/plugin/build/android.d.ts +36 -0
  197. package/plugin/build/android.js +265 -0
  198. package/plugin/build/index.d.ts +9 -0
  199. package/plugin/build/index.js +54 -0
  200. package/plugin/build/ios.d.ts +4 -0
  201. package/plugin/build/ios.js +43 -0
  202. package/plugin/build/options.d.ts +93 -0
  203. package/plugin/build/options.js +140 -0
  204. package/react-native.config.js +11 -0
  205. package/src/audio.ts +221 -0
  206. package/src/components.tsx +233 -0
  207. package/src/create-client.ts +53 -0
  208. package/src/errors.ts +81 -0
  209. package/src/globals.ts +54 -0
  210. package/src/index.ts +95 -0
  211. package/src/local-media.ts +420 -0
  212. package/src/native-session.tsx +338 -0
  213. package/src/native.ts +84 -0
  214. package/src/permissions.ts +173 -0
  215. package/src/platform/android.ts +128 -0
  216. package/src/platform/common.ts +157 -0
  217. package/src/platform/devices.ts +148 -0
  218. package/src/platform/index.ts +22 -0
  219. package/src/platform/ios.ts +48 -0
  220. package/src/platform/streams.ts +285 -0
  221. package/src/platform/timers.ts +72 -0
  222. package/src/platform/visibility.ts +59 -0
  223. package/src/preflight.ts +60 -0
  224. package/src/provider.tsx +86 -0
  225. package/src/specs/NativeVoltkitRtc.ts +180 -0
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withVoltkitAndroid = exports.META_SCREEN_SHARE = exports.META_HW_AEC = exports.META_AUDIO_MODE = exports.CALL_SERVICE_CLASS = void 0;
4
+ exports.blockedPermissions = blockedPermissions;
5
+ exports.planAndroid = planAndroid;
6
+ exports.setVoltkitManifest = setVoltkitManifest;
7
+ /**
8
+ * What the plugin writes into the app's AndroidManifest.xml (plan §5.5). The names are the ones the SDK's native side
9
+ * reads (android/src/main/java/com/voltkit/rtc/reactnative/):
10
+ *
11
+ * <uses-permission android:name="android.permission.CAMERA" /> unless android.camera is false
12
+ * <uses-permission android:name="android.permission.RECORD_AUDIO" />
13
+ * <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
14
+ * <uses-permission android:name="android.permission.INTERNET" />
15
+ * <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
16
+ * <!-- with the call service (android.callService, default on) -->
17
+ * <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
18
+ * <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
19
+ * <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
20
+ * <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
21
+ * <!-- for the permissions above, so Google Play does not read them as hardware the app cannot do without -->
22
+ * <uses-feature android:name="android.hardware.camera" android:required="false" /> with CAMERA
23
+ * <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
24
+ * <uses-feature android:name="android.hardware.camera.front" android:required="false" />
25
+ * <uses-feature android:name="android.hardware.microphone" android:required="false" /> with RECORD_AUDIO
26
+ * <application>
27
+ * <meta-data android:name="in.voltkit.rtc.AUDIO_MODE" android:value="communication" /> RtcConfig.kt
28
+ * <meta-data android:name="in.voltkit.rtc.HW_AEC" android:value="true" />
29
+ * <meta-data android:name="in.voltkit.rtc.SCREEN_SHARE" android:value="false" />
30
+ * <service android:name="com.voltkit.rtc.reactnative.VoltkitCallService" android:exported="false"
31
+ * android:foregroundServiceType="microphone|mediaPlayback" /> VoltkitCallService.kt
32
+ * </application>
33
+ *
34
+ * android.callServiceCamera adds the camera type and FOREGROUND_SERVICE_CAMERA; android.screenShare adds
35
+ * FOREGROUND_SERVICE_MEDIA_PROJECTION, SCREEN_SHARE=true and the mediaProjection type, and, without the call service,
36
+ * still FOREGROUND_SERVICE and POST_NOTIFICATIONS: react-native-webrtc's screen-capture service is a foreground service
37
+ * with a notification of its own. The call service's types are what it MAY take: CallServiceTypes.kt picks from them
38
+ * at run time (microphone when RECORD_AUDIO is granted, otherwise mediaPlayback; camera only with pauseCamera false;
39
+ * mediaProjection only while a screen share is live). POST_NOTIFICATIONS goes with any foreground service: from
40
+ * Android 13 its notification shows only once the user allows notifications (the service runs either way).
41
+ *
42
+ * The uses-feature entries: Google Play reads CAMERA as "needs a camera with autofocus" and RECORD_AUDIO as "needs a
43
+ * microphone" unless the manifest says otherwise, and hides the app from devices without them (tablets, TVs,
44
+ * Chromebooks, some car and kiosk devices): a voice-only app, or a listener, would vanish from them for a camera it
45
+ * never opens. The plugin marks each feature of the permissions it adds as not required (the front camera too, which
46
+ * calls use); a missing camera or microphone is reported at run time (media-unavailable). The app's own <uses-feature>
47
+ * entries, by android:name, are never changed, so an app that does require a camera keeps its android:required="true".
48
+ *
49
+ * The SDK's own library manifest has only INTERNET, ACCESS_NETWORK_STATE, MODIFY_AUDIO_SETTINGS and its init provider,
50
+ * so an app that turns the call service off takes on no foreground service at all.
51
+ *
52
+ * Never written, whatever the options: a Bluetooth permission (call audio routing needs none, as in the Android SDK),
53
+ * SYSTEM_ALERT_WINDOW (which the community react-native-webrtc plugin adds), VIBRATE or storage. Expo's template adds
54
+ * SYSTEM_ALERT_WINDOW, VIBRATE and the storage permissions to every app; they are not the plugin's, so it leaves them as
55
+ * they are, and the app drops them with "android.blockedPermissions" (PLAN_UPDATES 10; the docs show the list).
56
+ *
57
+ * The app's blocks win over the plugin: a permission in android.blockedPermissions (or already in the manifest with
58
+ * tools:node="remove") is never asked for again, and a call-service type that a block leaves unusable is not declared,
59
+ * with its FOREGROUND_SERVICE_* permission, e.g. a listen-only app that blocks RECORD_AUDIO gets a mediaPlayback-only
60
+ * service. Screen sharing goes the same way (SCREEN_SHARE=false, no mediaProjection type, a warning) when a block
61
+ * leaves react-native-webrtc's screen-capture service unable to run, i.e. FOREGROUND_SERVICE or, on Android 14 and
62
+ * later, FOREGROUND_SERVICE_MEDIA_PROJECTION: with SCREEN_SHARE=true the first share would crash the app (a
63
+ * SecurityException in that service's startForeground), where the SDK now raises screen-share-service-required.
64
+ * Expo's own blockedPermissions plugin runs before app plugins' manifest mods, so both orders are handled.
65
+ *
66
+ * GOOGLE PLAY. An app that targets Android 14 (API 34) or later and whose manifest declares foreground service types
67
+ * must declare each type in Play Console before it can publish (Monitor and improve > App content > Foreground service
68
+ * permissions; https://support.google.com/googleplay/android-developer/answer/13392821): for each type, the feature it
69
+ * serves, what happens to the user if the task is deferred or interrupted, and a link to a short video of a user
70
+ * starting it. With the defaults that is two types:
71
+ * - microphone: "Keeps the user's call audio going when they switch apps or turn the screen off during a call they
72
+ * started"; the video starts a call, goes to the home screen and keeps talking.
73
+ * - mediaPlayback: "Keeps a call audible for a listener who leaves the app"; the video joins as a listener, goes to
74
+ * the home screen and keeps listening.
75
+ * camera (android.callServiceCamera) and mediaProjection (android.screenShare; react-native-webrtc's
76
+ * MediaProjectionService declares it too) are declared the same way. android.callService: false declares no
77
+ * foreground service and needs no declaration, at the price of calls that drop about 6 s after the app leaves the screen
78
+ * (Android cuts a background app's network without one; Android 17 also blocks its background audio).
79
+ */
80
+ const config_plugins_1 = require("expo/config-plugins");
81
+ const options_1 = require("./options");
82
+ /** The SDK's call service (VoltkitCallService.kt); not exported: only the app itself starts it. */
83
+ exports.CALL_SERVICE_CLASS = 'com.voltkit.rtc.reactnative.VoltkitCallService';
84
+ /** The meta-data the SDK's init provider reads once when the app starts (RtcConfig.kt). */
85
+ exports.META_AUDIO_MODE = 'in.voltkit.rtc.AUDIO_MODE';
86
+ exports.META_HW_AEC = 'in.voltkit.rtc.HW_AEC';
87
+ exports.META_SCREEN_SHARE = 'in.voltkit.rtc.SCREEN_SHARE';
88
+ const permission = (name) => `android.permission.${name}`;
89
+ const CAMERA = permission('CAMERA');
90
+ const RECORD_AUDIO = permission('RECORD_AUDIO');
91
+ const FOREGROUND_SERVICE = permission('FOREGROUND_SERVICE');
92
+ const FOREGROUND_SERVICE_MEDIA_PROJECTION = permission('FOREGROUND_SERVICE_MEDIA_PROJECTION');
93
+ const POST_NOTIFICATIONS = permission('POST_NOTIFICATIONS');
94
+ const CALL_PERMISSIONS = ['RECORD_AUDIO', 'MODIFY_AUDIO_SETTINGS', 'INTERNET', 'ACCESS_NETWORK_STATE'].map(permission);
95
+ /**
96
+ * The device features Google Play reads from a permission as required unless the manifest says otherwise
97
+ * (developer.android.com/guide/topics/manifest/uses-feature-element, "Permissions that imply feature requirements"),
98
+ * plus the front camera, which calls use.
99
+ */
100
+ const FEATURES = [
101
+ {
102
+ permission: CAMERA,
103
+ features: ['android.hardware.camera', 'android.hardware.camera.autofocus', 'android.hardware.camera.front'],
104
+ },
105
+ { permission: RECORD_AUDIO, features: ['android.hardware.microphone'] },
106
+ ];
107
+ const SERVICE_TYPES = {
108
+ microphone: { permission: permission('FOREGROUND_SERVICE_MICROPHONE'), needs: [RECORD_AUDIO] },
109
+ mediaPlayback: { permission: permission('FOREGROUND_SERVICE_MEDIA_PLAYBACK'), needs: [] },
110
+ camera: { permission: permission('FOREGROUND_SERVICE_CAMERA'), needs: [CAMERA] },
111
+ mediaProjection: { permission: FOREGROUND_SERVICE_MEDIA_PROJECTION, needs: [] },
112
+ };
113
+ /** The permissions the app blocks: android.blockedPermissions, and entries with tools:node="remove" already there. */
114
+ function blockedPermissions(manifest, configBlocked = []) {
115
+ const blocked = new Set(configBlocked.map((name) => config_plugins_1.AndroidConfig.Permissions.ensurePermissionNameFormat(name)));
116
+ for (const entry of manifest.manifest['uses-permission'] ?? []) {
117
+ if (entry.$?.['tools:node'] === 'remove')
118
+ blocked.add(entry.$['android:name']);
119
+ }
120
+ return blocked;
121
+ }
122
+ function planAndroid(options, blocked) {
123
+ const usable = (...names) => names.every((name) => !blocked.has(name));
124
+ // react-native-webrtc's screen-capture service is a foreground service of type mediaProjection: without these it
125
+ // would crash the app at the first share (a SecurityException in its startForeground), so sharing stays off.
126
+ let screenShare = options.screenShare;
127
+ let screenShareDropped = null;
128
+ if (options.screenShare) {
129
+ const blocks = [FOREGROUND_SERVICE, FOREGROUND_SERVICE_MEDIA_PROJECTION].filter((name) => blocked.has(name));
130
+ if (blocks.length > 0) {
131
+ screenShare = false;
132
+ screenShareDropped = `android.blockedPermissions blocks ${blocks.join(' and ')}`;
133
+ }
134
+ }
135
+ let serviceTypes = [];
136
+ let serviceDropped = null;
137
+ if (options.callService) {
138
+ const wanted = ['microphone', 'mediaPlayback'];
139
+ if (options.callServiceCamera)
140
+ wanted.push('camera');
141
+ if (screenShare)
142
+ wanted.push('mediaProjection');
143
+ serviceTypes = wanted.filter((type) => usable(SERVICE_TYPES[type].permission, ...SERVICE_TYPES[type].needs));
144
+ if (!usable(FOREGROUND_SERVICE)) {
145
+ serviceDropped = `android.blockedPermissions blocks ${FOREGROUND_SERVICE}`;
146
+ }
147
+ else if (!serviceTypes.includes('microphone') && !serviceTypes.includes('mediaPlayback')) {
148
+ // CallServiceTypes.kt runs the service as microphone or mediaPlayback; camera or mediaProjection alone is no call.
149
+ const blocks = [RECORD_AUDIO, SERVICE_TYPES.microphone.permission, SERVICE_TYPES.mediaPlayback.permission].filter((name) => blocked.has(name));
150
+ serviceDropped = `android.blockedPermissions blocks ${blocks.join(', ')}, which leaves it neither the microphone nor the mediaPlayback type`;
151
+ }
152
+ if (serviceDropped)
153
+ serviceTypes = [];
154
+ }
155
+ // A foreground service of the app's: the call service, or react-native-webrtc's screen-capture service.
156
+ const foregroundService = serviceTypes.length > 0 || screenShare;
157
+ const wanted = [];
158
+ if (options.camera)
159
+ wanted.push(CAMERA);
160
+ wanted.push(...CALL_PERMISSIONS);
161
+ if (foregroundService)
162
+ wanted.push(FOREGROUND_SERVICE);
163
+ for (const type of serviceTypes)
164
+ wanted.push(SERVICE_TYPES[type].permission);
165
+ // react-native-webrtc's own screen-capture service needs it too, with or without the call service.
166
+ if (screenShare)
167
+ wanted.push(FOREGROUND_SERVICE_MEDIA_PROJECTION);
168
+ // Every foreground service has a notification, which Android 13 and later show only once the user allows them.
169
+ if (foregroundService)
170
+ wanted.push(POST_NOTIFICATIONS);
171
+ const permissions = [...new Set(wanted)].filter((name) => usable(name));
172
+ const features = FEATURES.flatMap((entry) => (permissions.includes(entry.permission) ? entry.features : []));
173
+ return { permissions, features, serviceTypes, serviceDropped, screenShare, screenShareDropped };
174
+ }
175
+ /**
176
+ * Marks these device features as not required, leaving the app's own <uses-feature> entries (by android:name) as they
177
+ * are. A manifest without any gets the list right before <application>, which the manifest must keep as its last
178
+ * child: xml2js writes the children in key order, and Expo's ensurePermissions appends a manifest's first
179
+ * <uses-permission> after <application>, so the rebuilt order ends with <application> whatever came before.
180
+ */
181
+ function setUsesFeatures(manifest, names) {
182
+ const root = manifest.manifest;
183
+ const existing = root['uses-feature'];
184
+ const declared = new Set((existing ?? []).map((entry) => entry.$?.['android:name']));
185
+ const added = names
186
+ .filter((name) => !declared.has(name))
187
+ .map((name) => ({ $: { 'android:name': name, 'android:required': 'false' } }));
188
+ if (added.length === 0)
189
+ return;
190
+ if (existing) {
191
+ existing.push(...added);
192
+ return;
193
+ }
194
+ const ordered = {};
195
+ for (const [key, value] of Object.entries(root)) {
196
+ if (key !== 'application')
197
+ ordered[key] = value;
198
+ }
199
+ ordered['uses-feature'] = added;
200
+ if ('application' in root)
201
+ ordered.application = root.application;
202
+ manifest.manifest = ordered;
203
+ }
204
+ /** Declares the call service with these types, in place (an earlier prebuild's entry is updated), or takes it out. */
205
+ function setCallService(application, types) {
206
+ const services = application.service ?? [];
207
+ const isCallService = (service) => service.$?.['android:name'] === exports.CALL_SERVICE_CLASS;
208
+ if (types.length === 0) {
209
+ const others = services.filter((service) => !isCallService(service));
210
+ if (others.length > 0)
211
+ application.service = others;
212
+ else
213
+ delete application.service;
214
+ return;
215
+ }
216
+ const attributes = {
217
+ 'android:name': exports.CALL_SERVICE_CLASS,
218
+ 'android:exported': 'false',
219
+ 'android:foregroundServiceType': types.join('|'),
220
+ };
221
+ let written = false;
222
+ const next = [];
223
+ for (const service of services) {
224
+ if (!isCallService(service))
225
+ next.push(service);
226
+ else if (!written) {
227
+ next.push({ ...service, $: { ...service.$, ...attributes } });
228
+ written = true;
229
+ }
230
+ }
231
+ if (!written)
232
+ next.push({ $: attributes });
233
+ application.service = next;
234
+ }
235
+ /**
236
+ * Writes the permissions, the device features, the meta-data and the call service for these options into the manifest.
237
+ * Running it again on its own output changes nothing; after an option changes, the meta-data and the service are
238
+ * updated in place.
239
+ */
240
+ function setVoltkitManifest(manifest, options, configBlocked = []) {
241
+ const plan = planAndroid(options, blockedPermissions(manifest, configBlocked));
242
+ // ensurePermissions skips a name already listed, including a tools:node="remove" block.
243
+ config_plugins_1.AndroidConfig.Permissions.ensurePermissions(manifest, plan.permissions);
244
+ setUsesFeatures(manifest, plan.features);
245
+ const application = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(manifest);
246
+ config_plugins_1.AndroidConfig.Manifest.addMetaDataItemToMainApplication(application, exports.META_AUDIO_MODE, options.audioMode);
247
+ config_plugins_1.AndroidConfig.Manifest.addMetaDataItemToMainApplication(application, exports.META_HW_AEC, String(options.hardwareEchoCancellation));
248
+ config_plugins_1.AndroidConfig.Manifest.addMetaDataItemToMainApplication(application, exports.META_SCREEN_SHARE, String(plan.screenShare));
249
+ setCallService(application, plan.serviceTypes);
250
+ if (plan.serviceDropped) {
251
+ config_plugins_1.WarningAggregator.addWarningAndroid(`${options_1.PLUGIN_NAME} android.callService`, `VoltkitCallService is not declared: ${plan.serviceDropped}. Calls will drop a few seconds after the app leaves ` +
252
+ 'the screen; unblock those permissions, or set android.callService to false to silence this.');
253
+ }
254
+ if (plan.screenShareDropped) {
255
+ config_plugins_1.WarningAggregator.addWarningAndroid(`${options_1.PLUGIN_NAME} android.screenShare`, `screen sharing is off (${exports.META_SCREEN_SHARE}=false): ${plan.screenShareDropped}, which react-native-webrtc's ` +
256
+ 'screen-capture service needs; with it on, the first share would crash the app. Unblock those permissions, or ' +
257
+ 'set android.screenShare to false to silence this.');
258
+ }
259
+ return manifest;
260
+ }
261
+ const withVoltkitAndroid = (config, options) => (0, config_plugins_1.withAndroidManifest)(config, (modConfig) => {
262
+ modConfig.modResults = setVoltkitManifest(modConfig.modResults, options, modConfig.android?.blockedPermissions ?? []);
263
+ return modConfig;
264
+ });
265
+ exports.withVoltkitAndroid = withVoltkitAndroid;
@@ -0,0 +1,9 @@
1
+ import type { ConfigPlugin } from 'expo/config-plugins';
2
+ import type { VoltkitRtcPluginProps } from './options';
3
+ declare const _default: ConfigPlugin<void | VoltkitRtcPluginProps | null>;
4
+ export default _default;
5
+ export { CALL_SERVICE_CLASS, META_AUDIO_MODE, META_HW_AEC, META_SCREEN_SHARE, blockedPermissions, planAndroid, setVoltkitManifest, withVoltkitAndroid, } from './android';
6
+ export type { AndroidPlan } from './android';
7
+ export { setVoltkitInfoPlist, withVoltkitIos } from './ios';
8
+ export { DEFAULT_CAMERA_PERMISSION, DEFAULT_MICROPHONE_PERMISSION, PLUGIN_NAME, resolveOptions } from './options';
9
+ export type { AndroidOptions, AudioMode, IosOptions, PluginOptions, VoltkitRtcAndroidProps, VoltkitRtcIosProps, VoltkitRtcPluginProps, } from './options';
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveOptions = exports.PLUGIN_NAME = exports.DEFAULT_MICROPHONE_PERMISSION = exports.DEFAULT_CAMERA_PERMISSION = exports.withVoltkitIos = exports.setVoltkitInfoPlist = exports.withVoltkitAndroid = exports.setVoltkitManifest = exports.planAndroid = exports.blockedPermissions = exports.META_SCREEN_SHARE = exports.META_HW_AEC = exports.META_AUDIO_MODE = exports.CALL_SERVICE_CLASS = void 0;
4
+ /**
5
+ * The Expo config plugin of @voltkit-rtc/react-native (plan §5.5). An app lists it in app.json:
6
+ *
7
+ * "plugins": [["@voltkit-rtc/react-native", { "android": { "callService": true } }]]
8
+ *
9
+ * and `npx expo prebuild` (or `npx expo run:android`) writes the permissions, the call service and the meta-data the SDK
10
+ * reads into AndroidManifest.xml (./android.ts), and the usage strings and background modes into Info.plist (./ios.ts):
11
+ * the app edits no native file. Self-sufficient: no @config-plugins/react-native-webrtc, whose table stops at Expo 56
12
+ * and which adds SYSTEM_ALERT_WINDOW. Options are checked when the plugin is applied (./options.ts).
13
+ *
14
+ * Expo finds it through app.plugin.js at the package root, which loads plugin/build (this file, built by
15
+ * `npm run build:plugin`). It runs once per app, under the package's name, even if app.json lists it twice.
16
+ */
17
+ const config_plugins_1 = require("expo/config-plugins");
18
+ const android_1 = require("./android");
19
+ const ios_1 = require("./ios");
20
+ const options_1 = require("./options");
21
+ /** The package's version, for Expo's plugin history (`expo config` shows it); from src/ and build/ alike. */
22
+ function packageVersion() {
23
+ try {
24
+ const version = require('../../package.json').version;
25
+ return typeof version === 'string' ? version : undefined;
26
+ }
27
+ catch {
28
+ return undefined;
29
+ }
30
+ }
31
+ const withVoltkitRtc = (config, props) => {
32
+ const options = (0, options_1.resolveOptions)(props);
33
+ config = (0, android_1.withVoltkitAndroid)(config, options.android);
34
+ config = (0, ios_1.withVoltkitIos)(config, options.ios);
35
+ return config;
36
+ };
37
+ exports.default = (0, config_plugins_1.createRunOncePlugin)(withVoltkitRtc, options_1.PLUGIN_NAME, packageVersion());
38
+ var android_2 = require("./android");
39
+ Object.defineProperty(exports, "CALL_SERVICE_CLASS", { enumerable: true, get: function () { return android_2.CALL_SERVICE_CLASS; } });
40
+ Object.defineProperty(exports, "META_AUDIO_MODE", { enumerable: true, get: function () { return android_2.META_AUDIO_MODE; } });
41
+ Object.defineProperty(exports, "META_HW_AEC", { enumerable: true, get: function () { return android_2.META_HW_AEC; } });
42
+ Object.defineProperty(exports, "META_SCREEN_SHARE", { enumerable: true, get: function () { return android_2.META_SCREEN_SHARE; } });
43
+ Object.defineProperty(exports, "blockedPermissions", { enumerable: true, get: function () { return android_2.blockedPermissions; } });
44
+ Object.defineProperty(exports, "planAndroid", { enumerable: true, get: function () { return android_2.planAndroid; } });
45
+ Object.defineProperty(exports, "setVoltkitManifest", { enumerable: true, get: function () { return android_2.setVoltkitManifest; } });
46
+ Object.defineProperty(exports, "withVoltkitAndroid", { enumerable: true, get: function () { return android_2.withVoltkitAndroid; } });
47
+ var ios_2 = require("./ios");
48
+ Object.defineProperty(exports, "setVoltkitInfoPlist", { enumerable: true, get: function () { return ios_2.setVoltkitInfoPlist; } });
49
+ Object.defineProperty(exports, "withVoltkitIos", { enumerable: true, get: function () { return ios_2.withVoltkitIos; } });
50
+ var options_2 = require("./options");
51
+ Object.defineProperty(exports, "DEFAULT_CAMERA_PERMISSION", { enumerable: true, get: function () { return options_2.DEFAULT_CAMERA_PERMISSION; } });
52
+ Object.defineProperty(exports, "DEFAULT_MICROPHONE_PERMISSION", { enumerable: true, get: function () { return options_2.DEFAULT_MICROPHONE_PERMISSION; } });
53
+ Object.defineProperty(exports, "PLUGIN_NAME", { enumerable: true, get: function () { return options_2.PLUGIN_NAME; } });
54
+ Object.defineProperty(exports, "resolveOptions", { enumerable: true, get: function () { return options_2.resolveOptions; } });
@@ -0,0 +1,4 @@
1
+ import type { ConfigPlugin, InfoPlist } from 'expo/config-plugins';
2
+ import type { IosOptions } from './options';
3
+ export declare function setVoltkitInfoPlist(plist: InfoPlist, options: IosOptions): InfoPlist;
4
+ export declare const withVoltkitIos: ConfigPlugin<IosOptions>;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withVoltkitIos = void 0;
4
+ exports.setVoltkitInfoPlist = setVoltkitInfoPlist;
5
+ /**
6
+ * What the plugin writes into the app's Info.plist (plan §5.5; the SDK's iOS side is a preview, JavaScript only):
7
+ *
8
+ * NSCameraUsageDescription cameraPermission, else the app's own text, else a short default
9
+ * NSMicrophoneUsageDescription microphonePermission, else the app's own text, else a short default
10
+ * UIBackgroundModes + "audio" (ios.backgroundAudio, default on), + "voip" (ios.voip, default off)
11
+ *
12
+ * It only adds: the app's other background modes stay, none is listed twice, and running it again changes nothing.
13
+ */
14
+ const config_plugins_1 = require("expo/config-plugins");
15
+ const options_1 = require("./options");
16
+ function usageText(given, current, fallback) {
17
+ if (given !== undefined)
18
+ return given;
19
+ if (typeof current === 'string' && current.trim() !== '')
20
+ return current;
21
+ return fallback;
22
+ }
23
+ function setVoltkitInfoPlist(plist, options) {
24
+ plist.NSCameraUsageDescription = usageText(options.cameraPermission, plist.NSCameraUsageDescription, options_1.DEFAULT_CAMERA_PERMISSION);
25
+ plist.NSMicrophoneUsageDescription = usageText(options.microphonePermission, plist.NSMicrophoneUsageDescription, options_1.DEFAULT_MICROPHONE_PERMISSION);
26
+ const modes = Array.isArray(plist.UIBackgroundModes) ? [...plist.UIBackgroundModes] : [];
27
+ const add = (mode) => {
28
+ if (!modes.includes(mode))
29
+ modes.push(mode);
30
+ };
31
+ if (options.backgroundAudio)
32
+ add('audio');
33
+ if (options.voip)
34
+ add('voip');
35
+ if (modes.length > 0)
36
+ plist.UIBackgroundModes = modes;
37
+ return plist;
38
+ }
39
+ const withVoltkitIos = (config, options) => (0, config_plugins_1.withInfoPlist)(config, (modConfig) => {
40
+ modConfig.modResults = setVoltkitInfoPlist(modConfig.modResults, options);
41
+ return modConfig;
42
+ });
43
+ exports.withVoltkitIos = withVoltkitIos;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * The Expo config plugin's options (plan §5.5), as an app writes them in app.json or app.config.ts:
3
+ *
4
+ * "plugins": [
5
+ * ["@voltkit-rtc/react-native", {
6
+ * "cameraPermission": "Your camera is shown to the people in your call.",
7
+ * "microphonePermission": "Your microphone is heard by the people in your call.",
8
+ * "android": { "callService": true, "screenShare": false },
9
+ * "ios": { "backgroundAudio": true }
10
+ * }]
11
+ * ]
12
+ *
13
+ * Every option is optional. resolveOptions checks them when the plugin is applied, before any native file is written,
14
+ * and fills in the defaults; an unknown name or a wrong type stops prebuild with a message that names the option, so a
15
+ * typo never falls back to a default without a word.
16
+ */
17
+ export declare const PLUGIN_NAME = "@voltkit-rtc/react-native";
18
+ /** How the app plays call audio (meta-data in.voltkit.rtc.AUDIO_MODE; RtcConfig.kt). */
19
+ export type AudioMode = 'communication' | 'media';
20
+ export interface VoltkitRtcAndroidProps {
21
+ /**
22
+ * "communication" (default): call audio, echo cancellation, the earpiece, the loudspeaker and headsets. "media", for
23
+ * an app whose users only ever listen: the media volume and Bluetooth's high-quality profile, no earpiece. Fixed for
24
+ * the life of the app's process; never "media" where anyone may speak.
25
+ */
26
+ audioMode?: AudioMode;
27
+ /**
28
+ * Declares CAMERA (default true), with the camera, its autofocus and the front camera marked as hardware the app
29
+ * can do without (uses-feature android:required="false", so Google Play does not hide the app from devices without
30
+ * them). false for an app that never publishes video.
31
+ */
32
+ camera?: boolean;
33
+ /**
34
+ * Declares the call service, VoltkitCallService, with the types microphone and mediaPlayback, and its permissions:
35
+ * FOREGROUND_SERVICE, FOREGROUND_SERVICE_MICROPHONE, FOREGROUND_SERVICE_MEDIA_PLAYBACK and POST_NOTIFICATIONS
36
+ * (default true, plan open decision 1). It keeps a call's network, microphone and sound going in the background and
37
+ * with the screen off. false declares no foreground service: Google Play then needs no foreground-service
38
+ * declaration, but a call drops a few seconds after the app leaves the screen.
39
+ */
40
+ callService?: boolean;
41
+ /**
42
+ * Adds the camera type to the call service and FOREGROUND_SERVICE_CAMERA (default false), for an app that keeps the
43
+ * camera on in the background (`background={{ pauseCamera: false }}` on the provider). Needs camera and callService.
44
+ */
45
+ callServiceCamera?: boolean;
46
+ /**
47
+ * Turns on react-native-webrtc's screen-capture service (meta-data in.voltkit.rtc.SCREEN_SHARE) and declares
48
+ * FOREGROUND_SERVICE_MEDIA_PROJECTION, plus the mediaProjection type on the call service, which takes it only while
49
+ * a share is live (default false). That service is a foreground service with a notification, so without the call
50
+ * service it still brings FOREGROUND_SERVICE and POST_NOTIFICATIONS. Stays off, with a warning, when
51
+ * android.blockedPermissions blocks what it needs.
52
+ */
53
+ screenShare?: boolean;
54
+ /** The phone's own echo canceller and noise suppressor, where it has them (meta-data in.voltkit.rtc.HW_AEC; default true). */
55
+ hardwareEchoCancellation?: boolean;
56
+ }
57
+ export interface VoltkitRtcIosProps {
58
+ /** Adds `audio` to UIBackgroundModes, so a call keeps its sound in the background (default true). */
59
+ backgroundAudio?: boolean;
60
+ /** Adds `voip` to UIBackgroundModes, for an app that integrates CallKit itself (default false). */
61
+ voip?: boolean;
62
+ }
63
+ export interface VoltkitRtcPluginProps {
64
+ /** The iOS camera prompt (NSCameraUsageDescription). Default: the app's own text, or a short one. */
65
+ cameraPermission?: string;
66
+ /** The iOS microphone prompt (NSMicrophoneUsageDescription). Default: the app's own text, or a short one. */
67
+ microphonePermission?: string;
68
+ android?: VoltkitRtcAndroidProps;
69
+ ios?: VoltkitRtcIosProps;
70
+ }
71
+ export interface AndroidOptions {
72
+ audioMode: AudioMode;
73
+ camera: boolean;
74
+ callService: boolean;
75
+ callServiceCamera: boolean;
76
+ screenShare: boolean;
77
+ hardwareEchoCancellation: boolean;
78
+ }
79
+ export interface IosOptions {
80
+ /** Absent: keep the Info.plist's own text, or write the default. */
81
+ cameraPermission?: string;
82
+ microphonePermission?: string;
83
+ backgroundAudio: boolean;
84
+ voip: boolean;
85
+ }
86
+ export interface PluginOptions {
87
+ android: AndroidOptions;
88
+ ios: IosOptions;
89
+ }
90
+ export declare const DEFAULT_CAMERA_PERMISSION = "Allow $(PRODUCT_NAME) to use your camera in calls.";
91
+ export declare const DEFAULT_MICROPHONE_PERMISSION = "Allow $(PRODUCT_NAME) to use your microphone in calls.";
92
+ /** The app's options, checked, with every default filled in. */
93
+ export declare function resolveOptions(props: unknown): PluginOptions;
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ /**
3
+ * The Expo config plugin's options (plan §5.5), as an app writes them in app.json or app.config.ts:
4
+ *
5
+ * "plugins": [
6
+ * ["@voltkit-rtc/react-native", {
7
+ * "cameraPermission": "Your camera is shown to the people in your call.",
8
+ * "microphonePermission": "Your microphone is heard by the people in your call.",
9
+ * "android": { "callService": true, "screenShare": false },
10
+ * "ios": { "backgroundAudio": true }
11
+ * }]
12
+ * ]
13
+ *
14
+ * Every option is optional. resolveOptions checks them when the plugin is applied, before any native file is written,
15
+ * and fills in the defaults; an unknown name or a wrong type stops prebuild with a message that names the option, so a
16
+ * typo never falls back to a default without a word.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.DEFAULT_MICROPHONE_PERMISSION = exports.DEFAULT_CAMERA_PERMISSION = exports.PLUGIN_NAME = void 0;
20
+ exports.resolveOptions = resolveOptions;
21
+ exports.PLUGIN_NAME = '@voltkit-rtc/react-native';
22
+ exports.DEFAULT_CAMERA_PERMISSION = 'Allow $(PRODUCT_NAME) to use your camera in calls.';
23
+ exports.DEFAULT_MICROPHONE_PERMISSION = 'Allow $(PRODUCT_NAME) to use your microphone in calls.';
24
+ const AUDIO_MODES = ['communication', 'media'];
25
+ const ANDROID_DEFAULTS = {
26
+ audioMode: 'communication',
27
+ camera: true,
28
+ callService: true,
29
+ callServiceCamera: false,
30
+ screenShare: false,
31
+ hardwareEchoCancellation: true,
32
+ };
33
+ const IOS_DEFAULTS = { backgroundAudio: true, voip: false };
34
+ const TOP_KEYS = ['cameraPermission', 'microphonePermission', 'android', 'ios'];
35
+ const ANDROID_KEYS = Object.keys(ANDROID_DEFAULTS);
36
+ const IOS_KEYS = Object.keys(IOS_DEFAULTS);
37
+ /** Every option by its full name, for "did you mean" when one is in the wrong place or misspelt. */
38
+ const FULL_NAMES = [
39
+ 'cameraPermission',
40
+ 'microphonePermission',
41
+ ...ANDROID_KEYS.map((key) => `android.${key}`),
42
+ ...IOS_KEYS.map((key) => `ios.${key}`),
43
+ ];
44
+ function fail(problem) {
45
+ throw new Error(`${exports.PLUGIN_NAME} config plugin: ${problem}${/[.?]$/.test(problem) ? '' : '.'}`);
46
+ }
47
+ function isObject(value) {
48
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
49
+ }
50
+ function show(value) {
51
+ if (value === undefined)
52
+ return 'undefined';
53
+ if (Array.isArray(value))
54
+ return 'an array';
55
+ if (typeof value === 'object' && value !== null)
56
+ return 'an object';
57
+ return JSON.stringify(value);
58
+ }
59
+ /** Refuses a name this scope does not have, pointing at the right one when it is elsewhere or differs only in case. */
60
+ function checkKeys(props, known, scope) {
61
+ for (const key of Object.keys(props)) {
62
+ if (known.includes(key))
63
+ continue;
64
+ const name = scope ? `${scope}.${key}` : key;
65
+ const near = FULL_NAMES.find((full) => full.split('.').pop()?.toLowerCase() === key.toLowerCase());
66
+ if (near)
67
+ fail(`unknown option "${name}"; did you mean "${near}"?`);
68
+ fail(`unknown option "${name}"; the ${scope ? `${scope} options are` : 'options are'} ${known.join(', ')}`);
69
+ }
70
+ }
71
+ function bool(props, key, scope, fallback) {
72
+ if (!(key in props) || props[key] === undefined)
73
+ return fallback;
74
+ const value = props[key];
75
+ if (typeof value !== 'boolean')
76
+ fail(`${scope}.${key} must be true or false, not ${show(value)}`);
77
+ return value;
78
+ }
79
+ function text(props, key, what) {
80
+ if (!(key in props) || props[key] === undefined)
81
+ return undefined;
82
+ const value = props[key];
83
+ if (typeof value !== 'string' || value.trim() === '')
84
+ fail(`${key} must be a non-empty string (${what}), not ${show(value)}`);
85
+ return value;
86
+ }
87
+ function section(props, key) {
88
+ const value = props[key];
89
+ if (value === undefined)
90
+ return {};
91
+ if (!isObject(value))
92
+ fail(`${key} must be an object, like "${key}": { ... }, not ${show(value)}`);
93
+ return value;
94
+ }
95
+ /** The app's options, checked, with every default filled in. */
96
+ function resolveOptions(props) {
97
+ if (props === undefined || props === null)
98
+ props = {};
99
+ if (!isObject(props)) {
100
+ fail(`its options must be an object, like ["${exports.PLUGIN_NAME}", { "android": { "callService": true } }], not ${show(props)}`);
101
+ }
102
+ checkKeys(props, TOP_KEYS, '');
103
+ const androidProps = section(props, 'android');
104
+ checkKeys(androidProps, ANDROID_KEYS, 'android');
105
+ const iosProps = section(props, 'ios');
106
+ checkKeys(iosProps, IOS_KEYS, 'ios');
107
+ let audioMode = ANDROID_DEFAULTS.audioMode;
108
+ if (androidProps.audioMode !== undefined) {
109
+ const value = androidProps.audioMode;
110
+ if (!AUDIO_MODES.includes(value)) {
111
+ fail(`android.audioMode must be ${AUDIO_MODES.map((mode) => `"${mode}"`).join(' or ')}, not ${show(value)}`);
112
+ }
113
+ audioMode = value;
114
+ }
115
+ const android = {
116
+ audioMode,
117
+ camera: bool(androidProps, 'camera', 'android', ANDROID_DEFAULTS.camera),
118
+ callService: bool(androidProps, 'callService', 'android', ANDROID_DEFAULTS.callService),
119
+ callServiceCamera: bool(androidProps, 'callServiceCamera', 'android', ANDROID_DEFAULTS.callServiceCamera),
120
+ screenShare: bool(androidProps, 'screenShare', 'android', ANDROID_DEFAULTS.screenShare),
121
+ hardwareEchoCancellation: bool(androidProps, 'hardwareEchoCancellation', 'android', ANDROID_DEFAULTS.hardwareEchoCancellation),
122
+ };
123
+ if (android.callServiceCamera && !android.callService) {
124
+ fail('android.callServiceCamera needs android.callService: the camera type belongs to the call service');
125
+ }
126
+ if (android.callServiceCamera && !android.camera) {
127
+ fail('android.callServiceCamera needs android.camera: a camera foreground service needs the CAMERA permission');
128
+ }
129
+ const ios = {
130
+ backgroundAudio: bool(iosProps, 'backgroundAudio', 'ios', IOS_DEFAULTS.backgroundAudio),
131
+ voip: bool(iosProps, 'voip', 'ios', IOS_DEFAULTS.voip),
132
+ };
133
+ const cameraPermission = text(props, 'cameraPermission', "the iOS camera prompt's text");
134
+ const microphonePermission = text(props, 'microphonePermission', "the iOS microphone prompt's text");
135
+ if (cameraPermission !== undefined)
136
+ ios.cameraPermission = cameraPermission;
137
+ if (microphonePermission !== undefined)
138
+ ios.microphonePermission = microphonePermission;
139
+ return { android, ios };
140
+ }
@@ -0,0 +1,11 @@
1
+ // How the React Native CLI and Expo autolink this package.
2
+ // Android: the TurboModule (VoltkitRtcPackage) and the init provider in android/. The codegen spec is
3
+ // src/specs/NativeVoltkitRtc.ts (package.json codegenConfig); the app runs codegen for it at build time.
4
+ // iOS: JavaScript only in 0.1.0, with no podspec, so there is nothing to link.
5
+ module.exports = {
6
+ dependency: {
7
+ platforms: {
8
+ ios: null,
9
+ },
10
+ },
11
+ };