@voltkit-rtc/react-native 0.0.0-stage → 0.1.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 (225) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1608 -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 +365 -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 +75 -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 +360 -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 +70 -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 +384 -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 +88 -0
  225. package/src/specs/NativeVoltkitRtc.ts +180 -0
@@ -0,0 +1,313 @@
1
+ package com.voltkit.rtc.reactnative
2
+
3
+ import android.Manifest
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.content.pm.PackageManager
7
+ import android.os.Build
8
+ import android.os.Handler
9
+ import android.os.Looper
10
+ import androidx.core.content.ContextCompat
11
+ import com.facebook.react.bridge.Arguments
12
+ import com.facebook.react.bridge.Promise
13
+ import com.facebook.react.bridge.ReactApplicationContext
14
+ import com.facebook.react.bridge.ReadableMap
15
+ import com.facebook.react.bridge.WritableArray
16
+ import com.facebook.react.bridge.WritableMap
17
+ import com.oney.WebRTCModule.MediaProjectionService
18
+ import com.oney.WebRTCModule.WebRTCModuleOptions
19
+ import org.webrtc.audio.JavaAudioDeviceModule
20
+ import java.util.concurrent.atomic.AtomicBoolean
21
+ import java.util.concurrent.atomic.AtomicInteger
22
+
23
+ /**
24
+ * The TurboModule behind src/specs/NativeVoltkitRtc.ts (plan §5.1): audio routing ([AudioRouter]), the call service
25
+ * ([VoltkitCallService]), native timers ([NativeTimers]), visibility ([AppVisibility]), the network ([NetworkWatch])
26
+ * and stopping react-native-webrtc's screen-share service once a share ends (Phase 0 finding 5).
27
+ *
28
+ * When the React instance goes away (a reload, the app closing), [invalidate] lets go of everything this instance
29
+ * holds: its audio holders, timers, watchers and the call service, since the JavaScript that ran the call is gone.
30
+ * Rejections carry a VoltKit error registry code (`bad-params`, `media-unavailable`) as their code.
31
+ */
32
+ class VoltkitRtcModule(reactContext: ReactApplicationContext) : NativeVoltkitRtcSpec(reactContext) {
33
+ private val app: Context = reactContext.applicationContext
34
+ private val config = VoltkitRtcInitProvider.configOf(app)
35
+ private val main = Handler(Looper.getMainLooper())
36
+
37
+ // --- audio ---------------------------------------------------------------------------------------------------
38
+ private val router: AudioRouter by lazy { AudioRouter.get(app, config.audioMode).also { it.addListener(audioListener) } }
39
+ private val holders = HashMap<Int, Any>()
40
+ private val nextHolder = AtomicInteger(0)
41
+ private val audioListener = object : AudioRouter.Listener {
42
+ override fun onDevicesChanged(change: DevicesChanged) {
43
+ emitOnAudioDevicesChanged(
44
+ Arguments.createMap().apply {
45
+ putArray("devices", devicesArray(change.devices))
46
+ putArray("added", devicesArray(change.added))
47
+ putArray("removed", devicesArray(change.removed))
48
+ },
49
+ )
50
+ }
51
+
52
+ override fun onOutputChanged(device: MediaDevice?) {
53
+ emitOnAudioOutputChanged(Arguments.createMap().apply { putDevice("device", device) })
54
+ }
55
+
56
+ override fun onFocusChanged(focus: String) {
57
+ emitOnAudioFocusChanged(Arguments.createMap().apply { putString("focus", focus) })
58
+ }
59
+ }
60
+ private val microphoneError: (String) -> Unit = { message ->
61
+ emitOnMicrophoneError(Arguments.createMap().apply { putString("message", message) })
62
+ }
63
+
64
+ // --- timers, visibility, network, the call service --------------------------------------------------------------
65
+ private val timerThread = HandlerScheduler("VoltKitTimers")
66
+ private val timers = NativeTimers(timerThread) { id -> emitOnTimer(id) }
67
+ private val network = NetworkWatch(app) { handover ->
68
+ emitOnNetworkAvailable(Arguments.createMap().apply { putBoolean("handover", handover) })
69
+ }
70
+ private val stopVisibility: () -> Unit = AppVisibility.watch { visible ->
71
+ emitOnAppVisibilityChanged(Arguments.createMap().apply { putBoolean("visible", visible) })
72
+ }
73
+ private val callServiceListener = VoltkitCallService.Listener { type, types, message ->
74
+ emitOnCallServiceEvent(
75
+ Arguments.createMap().apply {
76
+ putString("type", type)
77
+ putArray("types", Arguments.fromList(CallServiceTypes.names(types)))
78
+ putString("message", message)
79
+ },
80
+ )
81
+ }
82
+ private val invalidated = AtomicBoolean(false)
83
+
84
+ init {
85
+ network.start()
86
+ VoltkitRtcInitProvider.microphoneErrors.add(microphoneError)
87
+ VoltkitCallService.listeners.add(callServiceListener)
88
+ }
89
+
90
+ override fun getTypedExportedConstants(): MutableMap<String, Any> {
91
+ val declared = VoltkitCallService.declaredTypes(app)
92
+ return hashMapOf(
93
+ "audioMode" to config.audioMode.name,
94
+ "hardwareEchoCancellation" to config.hardwareEchoCancellation,
95
+ "screenShareEnabled" to (config.screenShare || WebRTCModuleOptions.getInstance().enableMediaProjectionService),
96
+ "callServiceDeclared" to (declared != null),
97
+ "callServiceTypes" to CallServiceTypes.names(declared ?: 0),
98
+ "sdkInt" to Build.VERSION.SDK_INT,
99
+ "nativeVersion" to BuildConfig.VOLTKIT_RTC_VERSION,
100
+ // True only while react-native-webrtc uses the module the init provider made (the audio mode and HW_AEC apply).
101
+ "audioDeviceModule" to VoltkitRtcInitProvider.audioDeviceModule.let {
102
+ it != null && it === WebRTCModuleOptions.getInstance().audioDeviceModule
103
+ },
104
+ )
105
+ }
106
+
107
+ // --- audio ---------------------------------------------------------------------------------------------------
108
+
109
+ override fun audioAcquire(speakerphone: Boolean?, promise: Promise) {
110
+ val id = nextHolder.incrementAndGet()
111
+ val token = Any()
112
+ synchronized(holders) { holders[id] = token }
113
+ router.acquire(token, speakerphone) { promise.resolve(id) }
114
+ }
115
+
116
+ override fun audioRelease(holder: Double) {
117
+ val token = synchronized(holders) { holders.remove(holder.toInt()) } ?: return
118
+ router.release(token)
119
+ }
120
+
121
+ override fun setSpeakerphoneOn(on: Boolean) {
122
+ router.setSpeakerphoneOn(on)
123
+ }
124
+
125
+ override fun listAudioDevices(promise: Promise) {
126
+ router.list { result ->
127
+ result.fold({ promise.resolve(devicesArray(it)) }, { promise.reject(E_MEDIA, "could not list the audio devices: ${it.message}", it) })
128
+ }
129
+ }
130
+
131
+ override fun selectAudioOutput(deviceId: String, promise: Promise) {
132
+ // In media mode sound follows the system's media routing: there is nothing to choose.
133
+ if (!router.isRouting) return promise.resolve(false)
134
+ router.selectOutput(deviceId) { result ->
135
+ result.fold({ promise.resolve(it) }, { promise.reject(E_MEDIA, "could not route call audio: ${it.message}", it) })
136
+ }
137
+ }
138
+
139
+ override fun selectAudioInput(deviceId: String?, promise: Promise) {
140
+ val adm = audioDeviceModule() ?: return promise.resolve(false)
141
+ if (deviceId == null) return promise.resolve(PreferredInput.clear(adm))
142
+ router.inputInfo(deviceId) { result ->
143
+ result.fold(
144
+ { info -> promise.resolve(info != null && PreferredInput.choose(adm, info)) },
145
+ { promise.reject(E_MEDIA, "could not choose the microphone: ${it.message}", it) },
146
+ )
147
+ }
148
+ }
149
+
150
+ override fun currentAudioOutput(promise: Promise) {
151
+ promise.resolve(router.output?.let(::deviceMap))
152
+ }
153
+
154
+ /**
155
+ * The audio device module react-native-webrtc plays and records with, when it is a JavaAudioDeviceModule: the init
156
+ * provider's, or one the app set itself. Never the provider's once the app replaced it, since WebRTC does not use it.
157
+ */
158
+ private fun audioDeviceModule(): JavaAudioDeviceModule? =
159
+ WebRTCModuleOptions.getInstance().audioDeviceModule as? JavaAudioDeviceModule
160
+
161
+ // --- visibility ----------------------------------------------------------------------------------------------
162
+
163
+ override fun isAppVisible(): Boolean = AppVisibility.visible
164
+
165
+ // --- the call service ----------------------------------------------------------------------------------------
166
+
167
+ override fun startCallService(options: ReadableMap, promise: Promise) = callService(options, start = true, promise)
168
+
169
+ override fun updateCallService(options: ReadableMap, promise: Promise) = callService(options, start = false, promise)
170
+
171
+ override fun stopCallService(promise: Promise) {
172
+ main.post {
173
+ VoltkitCallService.stop(app)
174
+ promise.resolve(callServiceStatus(running = false))
175
+ }
176
+ }
177
+
178
+ override fun getCallServiceStatus(): WritableMap = callServiceStatus()
179
+
180
+ private fun callService(options: ReadableMap, start: Boolean, promise: Promise) {
181
+ val declared = VoltkitCallService.declaredTypes(app)
182
+ ?: return promise.reject(
183
+ E_MEDIA,
184
+ "the app's manifest does not declare VoltkitCallService: turn on the Expo plugin's callService option, or add its <service> block (see the docs)",
185
+ )
186
+ val decision = CallServiceTypes.decide(
187
+ CallServiceTypes.Input(
188
+ sdkInt = Build.VERSION.SDK_INT,
189
+ declaredTypes = declared,
190
+ granted = grantedPermissions(),
191
+ audioMode = config.audioMode,
192
+ micPublished = options.flag("micPublished", true),
193
+ cameraPublished = options.flag("cameraPublished", false),
194
+ pauseCamera = options.flag("pauseCamera", true),
195
+ sharing = options.flag("sharing", false),
196
+ ),
197
+ )
198
+ if (!decision.canStart) return promise.reject(E_MEDIA, decision.reason ?: "the call service cannot run")
199
+ val request = VoltkitCallService.Request(
200
+ title = options.text("title", "Call in progress"),
201
+ text = options.text("text", "Tap to return to the call"),
202
+ leaveLabel = options.text("leaveLabel", "Leave"),
203
+ types = decision.types,
204
+ )
205
+ val done: (Result<Int>) -> Unit = { result ->
206
+ result.fold({ promise.resolve(callServiceStatus()) }, { promise.reject(E_MEDIA, it.message ?: "the call service could not start", it) })
207
+ }
208
+ main.post {
209
+ when {
210
+ VoltkitCallService.running != null -> VoltkitCallService.update(request, done)
211
+ !start -> promise.resolve(callServiceStatus())
212
+ // Android 12+ refuses a foreground service started from the background; say so plainly.
213
+ Build.VERSION.SDK_INT >= 31 && !AppVisibility.visible ->
214
+ promise.reject(E_MEDIA, "the app is in the background: Android lets the call service start only while the app is visible")
215
+ else -> VoltkitCallService.start(app, request, done)
216
+ }
217
+ }
218
+ }
219
+
220
+ private fun callServiceStatus(running: Boolean = VoltkitCallService.running != null): WritableMap = Arguments.createMap().apply {
221
+ putBoolean("declared", VoltkitCallService.declaredTypes(app) != null)
222
+ putBoolean("running", running)
223
+ putArray("types", Arguments.fromList(if (running) CallServiceTypes.names(VoltkitCallService.runningTypes) else emptyList<String>()))
224
+ }
225
+
226
+ private fun grantedPermissions(): Set<String> =
227
+ CALL_SERVICE_PERMISSIONS.filter { ContextCompat.checkSelfPermission(app, it) == PackageManager.PERMISSION_GRANTED }.toSet()
228
+
229
+ // --- screen share --------------------------------------------------------------------------------------------
230
+
231
+ override fun stopScreenShareService(promise: Promise) {
232
+ // react-native-webrtc stops its MediaProjectionService only when the screen track is released, and a stopped
233
+ // track is not released: the service outlived every share (Phase 0 finding 5).
234
+ val stopped = try {
235
+ app.stopService(Intent(app, MediaProjectionService::class.java))
236
+ } catch (_: Throwable) {
237
+ false
238
+ }
239
+ promise.resolve(stopped)
240
+ }
241
+
242
+ // --- native timers -------------------------------------------------------------------------------------------
243
+
244
+ override fun timerStart(id: Double, ms: Double, repeat: Boolean) {
245
+ if (invalidated.get()) return
246
+ timers.start(id, ms, repeat)
247
+ }
248
+
249
+ override fun timerStop(id: Double) {
250
+ timers.stop(id)
251
+ }
252
+
253
+ // --- the React instance went away ----------------------------------------------------------------------------
254
+
255
+ override fun invalidate() {
256
+ if (invalidated.compareAndSet(false, true)) {
257
+ timers.stopAll()
258
+ timerThread.quit()
259
+ stopVisibility()
260
+ network.stop()
261
+ VoltkitRtcInitProvider.microphoneErrors.remove(microphoneError)
262
+ VoltkitCallService.listeners.remove(callServiceListener)
263
+ val held = synchronized(holders) { holders.values.toList().also { holders.clear() } }
264
+ AudioRouter.existing()?.let { r ->
265
+ held.forEach { r.release(it) }
266
+ r.removeListener(audioListener)
267
+ }
268
+ main.post { VoltkitCallService.stop(app) }
269
+ }
270
+ super.invalidate()
271
+ }
272
+
273
+ // --- JavaScript values ---------------------------------------------------------------------------------------
274
+
275
+ private fun deviceMap(device: MediaDevice): WritableMap = Arguments.createMap().apply {
276
+ putString("deviceId", device.deviceId)
277
+ putString("kind", device.kind.name)
278
+ putString("label", device.label)
279
+ putString("type", (device.type ?: AudioDeviceType.other).name)
280
+ putString("groupId", device.groupId)
281
+ }
282
+
283
+ private fun devicesArray(devices: List<MediaDevice>): WritableArray = Arguments.createArray().apply {
284
+ devices.forEach { pushMap(deviceMap(it)) }
285
+ }
286
+
287
+ private fun WritableMap.putDevice(key: String, device: MediaDevice?) {
288
+ if (device == null) putNull(key) else putMap(key, deviceMap(device))
289
+ }
290
+
291
+ private fun ReadableMap.flag(key: String, default: Boolean): Boolean =
292
+ if (hasKey(key) && !isNull(key)) getBoolean(key) else default
293
+
294
+ private fun ReadableMap.text(key: String, default: String): String =
295
+ if (hasKey(key) && !isNull(key)) getString(key)?.takeIf { it.isNotBlank() } ?: default else default
296
+
297
+ companion object {
298
+ const val NAME = NativeVoltkitRtcSpec.NAME
299
+
300
+ /** Rejections use the VoltKit error registry's codes. */
301
+ private const val E_MEDIA = "media-unavailable"
302
+
303
+ private val CALL_SERVICE_PERMISSIONS = listOf(
304
+ Manifest.permission.FOREGROUND_SERVICE,
305
+ Manifest.permission.RECORD_AUDIO,
306
+ Manifest.permission.CAMERA,
307
+ Manifest.permission.FOREGROUND_SERVICE_MICROPHONE,
308
+ Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK,
309
+ Manifest.permission.FOREGROUND_SERVICE_CAMERA,
310
+ Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION,
311
+ )
312
+ }
313
+ }
@@ -0,0 +1,30 @@
1
+ package com.voltkit.rtc.reactnative
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+
9
+ /**
10
+ * What autolinking adds to the app's package list: the one TurboModule, VoltkitRtc (New Architecture only; React
11
+ * Native 0.82 and later have no other). Expo's and the React Native CLI's autolinking find this class by its
12
+ * declaration, `class VoltkitRtcPackage : BaseReactPackage()`.
13
+ */
14
+ class VoltkitRtcPackage : BaseReactPackage() {
15
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? =
16
+ if (name == VoltkitRtcModule.NAME) VoltkitRtcModule(reactContext) else null
17
+
18
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider {
19
+ mapOf(
20
+ VoltkitRtcModule.NAME to ReactModuleInfo(
21
+ name = VoltkitRtcModule.NAME,
22
+ className = VoltkitRtcModule::class.java.name,
23
+ canOverrideExistingModule = false,
24
+ needsEagerInit = false,
25
+ isCxxModule = false,
26
+ isTurboModule = true,
27
+ ),
28
+ )
29
+ }
30
+ }
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ The call notification's small icon when the app ships none of its own (VoltkitCallService.smallIcon): a white handset.
4
+ Android draws a small icon from its alpha channel only, so it must be a shape on transparency, never the launcher
5
+ icon. An app chooses its own by adding a drawable named voltkit_call_notification_icon.
6
+ -->
7
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
8
+ android:width="24dp"
9
+ android:height="24dp"
10
+ android:viewportWidth="24"
11
+ android:viewportHeight="24">
12
+ <path
13
+ android:fillColor="#FFFFFFFF"
14
+ android:pathData="M4.5,3L8.2,3C8.9,3 9.3,3.5 9.4,4.1L9.9,7.2C10,7.8 9.8,8.4 9.3,8.8L7.7,10.1C9,12.6 11.4,15 13.9,16.3L15.2,14.7C15.6,14.2 16.2,14 16.8,14.1L19.9,14.6C20.5,14.7 21,15.1 21,15.8L21,19.5C21,20.3 20.3,21 19.5,21C10.4,21 3,13.6 3,4.5C3,3.7 3.7,3 4.5,3Z" />
15
+ </vector>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ The call notification's icon is looked up by name in the app (VoltkitCallService.smallIcon), which resource shrinking
4
+ cannot see: keep the app's drawables of those names, when it has them. The SDK's own default is referenced from code.
5
+ -->
6
+ <resources xmlns:tools="http://schemas.android.com/tools"
7
+ tools:keep="@drawable/voltkit_call_notification_icon,@drawable/notification_icon,@drawable/ic_notification" />
package/app.plugin.js ADDED
@@ -0,0 +1,17 @@
1
+ // The Expo config plugin of @voltkit-rtc/react-native: Expo loads this file when app.json lists the package in
2
+ // "plugins". The plugin is TypeScript in plugin/src, built to plugin/build by `npm run build:plugin` (and by
3
+ // prepublishOnly, so a published package always carries it); see plugin/src/index.ts for what it writes.
4
+ try {
5
+ module.exports = require('./plugin/build');
6
+ } catch (error) {
7
+ // plugin/build is build output (git-ignored): in a checkout it has to be built first. Anything else (a missing expo,
8
+ // an error inside the build) is reported as it is.
9
+ if (error && error.code === 'MODULE_NOT_FOUND' && String(error.message).includes("Cannot find module './plugin/build'")) {
10
+ throw new Error(
11
+ "@voltkit-rtc/react-native: the Expo config plugin's build, plugin/build, is missing. A published package carries " +
12
+ 'it; in a checkout run `npm run build:plugin` in react-native-sdk first.',
13
+ { cause: error },
14
+ );
15
+ }
16
+ throw error;
17
+ }
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.audioHoldOf = audioHoldOf;
7
+ exports.selectAudioOutput = selectAudioOutput;
8
+ exports.setSpeakerphoneOn = setSpeakerphoneOn;
9
+ exports.speakerPreference = speakerPreference;
10
+ exports.useAudioOutput = useAudioOutput;
11
+ var _react = require("react");
12
+ var _reactNative = require("react-native");
13
+ var _client = require("@voltkit-rtc/client");
14
+ var _native = require("./native.js");
15
+ var _errors = require("./errors.js");
16
+ /**
17
+ * Call audio on Android: the speaker or the earpiece, headsets and Bluetooth, through this package's audio router (a
18
+ * port of the Android SDK's AudioRouter, AudioSwitch's rules). Process-wide, like Android's AudioManager: every
19
+ * connected client holds the call audio (the provider does it), and the last to let go puts the device's audio mode,
20
+ * speakerphone and microphone mute back as it found them. setSpeakerphoneOn and selectAudioOutput work before any
21
+ * client exists: the choice is kept for the call.
22
+ *
23
+ * In the audio mode `media` (the Expo plugin's android.audioMode, for apps whose users only listen) sound follows the
24
+ * system's media routing: there is no earpiece and nothing to choose. On iOS (preview) there is no routing at all.
25
+ */
26
+
27
+ /** Whether this app chose the speaker itself (setSpeakerphoneOn): the provider then leaves that choice alone. */
28
+ let speakerChosen = null;
29
+
30
+ /**
31
+ * Play call audio on the loudspeaker (true) or the earpiece (false) when no headset is connected; a wired or Bluetooth
32
+ * headset still wins. Kept until changed, and applied to calls joined later. Rejects with `media-unavailable` on iOS
33
+ * and where the native module is missing.
34
+ */
35
+ async function setSpeakerphoneOn(on) {
36
+ const module = (0, _native.requireNative)('Choosing the speaker or the earpiece');
37
+ module.setSpeakerphoneOn(Boolean(on));
38
+ speakerChosen = Boolean(on);
39
+ outputs.preferenceChanged();
40
+ }
41
+
42
+ /**
43
+ * Play call audio on this output (a deviceId from useAudioOutput().outputs) while it stays connected. Rejects with
44
+ * `bad-params` for an output that is not there and in the audio mode `media`, and with `media-unavailable` on iOS and
45
+ * where the native module is missing.
46
+ */
47
+ async function selectAudioOutput(deviceId) {
48
+ const module = (0, _native.requireNative)('Choosing the audio output');
49
+ let routed;
50
+ try {
51
+ routed = await module.selectAudioOutput(deviceId);
52
+ } catch (err) {
53
+ throw (0, _errors.nativeFailure)(err);
54
+ }
55
+ if (!routed) {
56
+ throw new _client.RpcError('bad-params', (0, _native.nativeConstants)()?.audioMode === 'media' ? 'in the audio mode media, sound follows the system\'s media routing: there is no output to choose' : `there is no audio output with the id ${deviceId}`);
57
+ }
58
+ }
59
+
60
+ /**
61
+ * The speaker preference a newly joined call holds the audio with: the provider's (default the loudspeaker), unless
62
+ * the app chose with setSpeakerphoneOn, which the router keeps (null).
63
+ */
64
+ function speakerPreference(provider) {
65
+ return speakerChosen !== null ? null : provider ?? true;
66
+ }
67
+
68
+ // ------------------------------------------------------------------------------------------- holding the call audio
69
+
70
+ /**
71
+ * One client's hold on the call audio: acquired once it is connected, released when it closes or the provider lets go
72
+ * of it. Released a moment late, so React's StrictMode (an effect unmounted and mounted again at once) neither
73
+ * releases nor acquires twice.
74
+ */
75
+ class AudioHold {
76
+ holder = null;
77
+ users = 0;
78
+ pendingRelease = false;
79
+ constructor(onError) {
80
+ this.onError = onError;
81
+ }
82
+ retain() {
83
+ this.users += 1;
84
+ this.pendingRelease = false;
85
+ }
86
+
87
+ /** One user less; the hold goes when none is left. */
88
+ unretain() {
89
+ this.users = Math.max(0, this.users - 1);
90
+ if (this.users > 0) return;
91
+ this.pendingRelease = true;
92
+ queueMicrotask(() => {
93
+ if (this.pendingRelease && this.users === 0) this.release();
94
+ });
95
+ }
96
+ acquire(speakerphone) {
97
+ if (this.holder) return;
98
+ const module = (0, _native.nativeModule)();
99
+ if (!module) return;
100
+ this.holder = module.audioAcquire(speakerphone).then(id => id, err => {
101
+ this.onError((0, _errors.nativeFailure)(err));
102
+ return null;
103
+ });
104
+ }
105
+ release() {
106
+ this.pendingRelease = false;
107
+ const holder = this.holder;
108
+ if (!holder) return;
109
+ this.holder = null;
110
+ void holder.then(id => {
111
+ if (id !== null) (0, _native.nativeModule)()?.audioRelease(id);
112
+ });
113
+ }
114
+ }
115
+ const holds = new WeakMap();
116
+
117
+ /** The call audio hold of `client`. */
118
+ function audioHoldOf(client, onError) {
119
+ let hold = holds.get(client);
120
+ if (!hold) {
121
+ hold = new AudioHold(onError);
122
+ holds.set(client, hold);
123
+ }
124
+ return hold;
125
+ }
126
+
127
+ // ------------------------------------------------------------------------------------------- useAudioOutput
128
+
129
+ const NONE = Object.freeze({
130
+ supported: false,
131
+ outputs: Object.freeze([]),
132
+ current: null,
133
+ speakerphone: false
134
+ });
135
+
136
+ /** The audio outputs, kept current from the router's events while something listens. */
137
+ class OutputStore {
138
+ state = NONE;
139
+ listeners = new Set();
140
+ stop = null;
141
+ subscribe = listener => {
142
+ this.listeners.add(listener);
143
+ if (this.listeners.size === 1) this.start();
144
+ return () => {
145
+ this.listeners.delete(listener);
146
+ if (this.listeners.size === 0) {
147
+ this.stop?.();
148
+ this.stop = null;
149
+ }
150
+ };
151
+ };
152
+ snapshot = () => this.state;
153
+
154
+ /** The app changed the speaker preference: what is shown before a call holds the audio follows it. */
155
+ preferenceChanged() {
156
+ if (this.listeners.size > 0) this.set({
157
+ ...this.state,
158
+ speakerphone: this.state.current ? this.state.current.type === 'speaker' : speakerChosen ?? true
159
+ });
160
+ }
161
+ start() {
162
+ const module = (0, _native.nativeModule)();
163
+ const supported = _reactNative.Platform.OS === 'android' && module !== null && (0, _native.nativeConstants)()?.audioMode !== 'media';
164
+ if (!module) {
165
+ this.set(NONE);
166
+ return;
167
+ }
168
+ this.set({
169
+ ...this.state,
170
+ supported,
171
+ speakerphone: this.state.current ? this.state.current.type === 'speaker' : speakerChosen ?? true
172
+ });
173
+ const stops = [(0, _native.listen)(module.onAudioDevicesChanged, 'onAudioDevicesChanged', e => this.setOutputs(e.devices.map(_native.toMediaDevice))), (0, _native.listen)(module.onAudioOutputChanged, 'onAudioOutputChanged', e => this.setCurrent(e.device ? (0, _native.toMediaDevice)(e.device) : null))];
174
+ this.stop = () => {
175
+ for (const stop of stops) stop();
176
+ };
177
+ module.listAudioDevices().then(list => this.setOutputs(list.map(_native.toMediaDevice)), err => (0, _errors.logError)('could not list the audio devices', err));
178
+ module.currentAudioOutput().then(device => this.setCurrent(device ? (0, _native.toMediaDevice)(device) : null), err => (0, _errors.logError)('could not read the audio output', err));
179
+ }
180
+ setOutputs(devices) {
181
+ const outputs = this.state.supported ? devices.filter(d => d.kind === 'audiooutput') : [];
182
+ const same = outputs.length === this.state.outputs.length && outputs.every((d, i) => d.deviceId === this.state.outputs[i].deviceId && d.label === this.state.outputs[i].label);
183
+ if (!same) this.set({
184
+ ...this.state,
185
+ outputs
186
+ });
187
+ }
188
+ setCurrent(device) {
189
+ if (device?.deviceId === this.state.current?.deviceId) return;
190
+ this.set({
191
+ ...this.state,
192
+ current: device,
193
+ speakerphone: device ? device.type === 'speaker' : speakerChosen ?? true
194
+ });
195
+ }
196
+ set(next) {
197
+ this.state = next;
198
+ for (const listener of [...this.listeners]) listener();
199
+ }
200
+ }
201
+ const outputs = new OutputStore();
202
+
203
+ /**
204
+ * Where call audio plays, and the choice of output (an Android "speaker / phone / headset" picker). Works before any
205
+ * call: a choice made then is kept. On iOS and without the native module `supported` is false and the calls reject.
206
+ */
207
+ function useAudioOutput() {
208
+ const state = (0, _react.useSyncExternalStore)(outputs.subscribe, outputs.snapshot, outputs.snapshot);
209
+ return (0, _react.useMemo)(() => ({
210
+ ...state,
211
+ select: selectAudioOutput,
212
+ setSpeakerphoneOn
213
+ }), [state]);
214
+ }
215
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","require","_reactNative","_client","_native","_errors","speakerChosen","setSpeakerphoneOn","on","module","requireNative","Boolean","outputs","preferenceChanged","selectAudioOutput","deviceId","routed","err","nativeFailure","RpcError","nativeConstants","audioMode","speakerPreference","provider","AudioHold","holder","users","pendingRelease","constructor","onError","retain","unretain","Math","max","queueMicrotask","release","acquire","speakerphone","nativeModule","audioAcquire","then","id","audioRelease","holds","WeakMap","audioHoldOf","client","hold","get","set","NONE","Object","freeze","supported","current","OutputStore","state","listeners","Set","stop","subscribe","listener","add","size","start","delete","snapshot","type","Platform","OS","stops","listen","onAudioDevicesChanged","e","setOutputs","devices","map","toMediaDevice","onAudioOutputChanged","setCurrent","device","listAudioDevices","list","logError","currentAudioOutput","filter","d","kind","same","length","every","i","label","next","useAudioOutput","useSyncExternalStore","useMemo","select"],"sourceRoot":"../../src","sources":["audio.ts"],"mappings":"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","ignoreList":[]}