@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,70 @@
1
+ // @voltkit-rtc/react-native for Android: one codegen TurboModule (audio routing, the call service, native timers,
2
+ // visibility, the network) and the init provider that gives react-native-webrtc its audio device module. Built by
3
+ // the app (autolinking): the app's build brings the Android Gradle plugin, Kotlin and React Native's plugin.
4
+ //
5
+ // It never depends on in.voltkit:voltkit-rtc, which bundles its own libwebrtc: two copies in one APK clash. The
6
+ // WebRTC here is react-native-webrtc's (org.jitsi:webrtc).
7
+
8
+ import groovy.json.JsonSlurper
9
+
10
+ def packageJson = new JsonSlurper().parse(file('../package.json'))
11
+
12
+ if (findProject(':react-native-webrtc') == null) {
13
+ throw new GradleException(
14
+ "@voltkit-rtc/react-native needs react-native-webrtc: npm install react-native-webrtc, then rebuild the app"
15
+ )
16
+ }
17
+
18
+ apply plugin: 'com.android.library'
19
+
20
+ // Android Gradle plugin 9 compiles Kotlin itself unless the app opts out (android.builtInKotlin=false, as Expo's
21
+ // template does); before 9, and when opted out, the Kotlin plugin does.
22
+ def agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger()
23
+ def builtInKotlin = agpMajor >= 9 && (findProperty('android.builtInKotlin') ?: 'true').toString() != 'false'
24
+ if (!builtInKotlin) {
25
+ apply plugin: 'org.jetbrains.kotlin.android'
26
+ }
27
+
28
+ // Runs codegen for src/specs/NativeVoltkitRtc.ts (package.json codegenConfig) and compiles its Java base class.
29
+ apply plugin: 'com.facebook.react'
30
+
31
+ def safeExtGet(prop, fallback) {
32
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
33
+ }
34
+
35
+ android {
36
+ namespace = "com.voltkit.rtc.reactnative"
37
+ compileSdk = safeExtGet('compileSdkVersion', 36)
38
+
39
+ defaultConfig {
40
+ minSdk = 24
41
+ consumerProguardFiles 'consumer-rules.pro'
42
+ buildConfigField "String", "VOLTKIT_RTC_VERSION", "\"${packageJson.version}\""
43
+ }
44
+
45
+ buildFeatures {
46
+ buildConfig = true
47
+ }
48
+
49
+ compileOptions {
50
+ sourceCompatibility = JavaVersion.VERSION_17
51
+ targetCompatibility = JavaVersion.VERSION_17
52
+ }
53
+
54
+ testOptions {
55
+ // The JVM tests touch only android.* constants; the stubs must not throw if anything else is reached.
56
+ unitTests.returnDefaultValues = true
57
+ }
58
+ }
59
+
60
+ dependencies {
61
+ implementation 'com.facebook.react:react-android'
62
+ // WebRTCModuleOptions (the audio device module, the screen-share service) and org.webrtc's JavaAudioDeviceModule.
63
+ implementation project(':react-native-webrtc')
64
+ // ProcessLifecycleOwner, for visibility (the Android SDK's pin).
65
+ implementation 'androidx.lifecycle:lifecycle-process:2.10.0'
66
+ // ServiceCompat.startForeground with types (1.12+); NotificationCompat.
67
+ implementation 'androidx.core:core:1.13.1'
68
+
69
+ testImplementation 'junit:junit:4.13.2'
70
+ }
@@ -0,0 +1,21 @@
1
+ # @voltkit-rtc/react-native: consumer rules, applied to every app that depends on it. Apps add nothing for the SDK.
2
+
3
+ # react-native-webrtc 155.0.1 brings org.jitsi:webrtc 155.0.1, whose libwebrtc.jar has org.webrtc.Dav1dDecoderJni
4
+ # without org.webrtc.Dav1dDecoder$Natives. react-native-webrtc's own rules keep org.webrtc.** but do not silence
5
+ # that, so every R8 release build fails with "Missing class org.webrtc.Dav1dDecoder$Natives (referenced from:
6
+ # org.webrtc.Dav1dDecoderJni.get() ...)" (Phase 0, finding 2). Nothing calls it: the AV1 decoder that ships is
7
+ # libaom's.
8
+ -dontwarn org.webrtc.Dav1dDecoder$Natives
9
+
10
+ # selectAudioInput(null) goes back to the default microphone through JavaAudioDeviceModule's recorder, by reflection:
11
+ # its public setPreferredInputDevice(null) throws in jitsi's WebRTC 155 (it logs the device's id first).
12
+ # react-native-webrtc's rules keep org.webrtc.** already; these keep the two members even if that changes.
13
+ -keepclassmembers class org.webrtc.audio.JavaAudioDeviceModule {
14
+ org.webrtc.audio.WebRtcAudioRecord audioInput;
15
+ }
16
+ -keepclassmembers class org.webrtc.audio.WebRtcAudioRecord {
17
+ void setPreferredDevice(android.media.AudioDeviceInfo);
18
+ }
19
+
20
+ # Nothing else is needed: React Native's rules keep every NativeModule (VoltkitRtcModule and its codegen base class),
21
+ # and the manifest keeps the provider and the call service.
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+
4
+ <!--
5
+ Only what every app using @voltkit-rtc/react-native needs, as the Android SDK's manifest. CAMERA and
6
+ RECORD_AUDIO are left to the app (a viewer-only app should not declare them), and so is the call service with
7
+ its FOREGROUND_SERVICE permissions (the Expo plugin's callService option, or the manifest block in the docs):
8
+ an app that never runs background calls takes on no Play declaration.
9
+ -->
10
+ <uses-permission android:name="android.permission.INTERNET" />
11
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
12
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
13
+
14
+ <application>
15
+ <!--
16
+ Gives react-native-webrtc its audio device module (audio mode, echo cancellation) and turns on its
17
+ screen-share service, from the in.voltkit.rtc.* meta-data, before react-native-webrtc starts.
18
+ -->
19
+ <provider
20
+ android:name="com.voltkit.rtc.reactnative.VoltkitRtcInitProvider"
21
+ android:authorities="${applicationId}.voltkitrtcinit"
22
+ android:exported="false" />
23
+ </application>
24
+
25
+ </manifest>
@@ -0,0 +1,67 @@
1
+ package com.voltkit.rtc.reactnative
2
+
3
+ import android.os.Handler
4
+ import android.os.Looper
5
+ import androidx.lifecycle.DefaultLifecycleObserver
6
+ import androidx.lifecycle.Lifecycle
7
+ import androidx.lifecycle.LifecycleOwner
8
+ import androidx.lifecycle.ProcessLifecycleOwner
9
+ import java.util.concurrent.CopyOnWriteArraySet
10
+ import java.util.concurrent.atomic.AtomicBoolean
11
+
12
+ /**
13
+ * Whether the app is in the foreground (any activity started), from the process lifecycle, which knows it from the
14
+ * start however late a client is made. A process with no activity at all (a call answered from a push, a service)
15
+ * counts as in the background. Ported unchanged from the Android SDK (android-sdk/.../AppVisibility.kt).
16
+ *
17
+ * Why not React Native's AppState: it says `background` while a permission dialog or the screen-share consent is
18
+ * open, though the app is still in front (Phase 0 S8: ProcessLifecycleOwner said ON_PAUSE only, never ON_STOP).
19
+ *
20
+ * The observer is registered through a post to the main looper, never in place: the init provider calls [install]
21
+ * while providers are being created, before androidx.startup's InitializationProvider starts the process lifecycle
22
+ * (S7/S8). The post runs after every provider and Application.onCreate.
23
+ */
24
+ internal object AppVisibility {
25
+ private val listeners = CopyOnWriteArraySet<(Boolean) -> Unit>()
26
+ private val installed = AtomicBoolean(false)
27
+
28
+ @Volatile
29
+ var visible: Boolean = true
30
+ private set
31
+
32
+ /** Hear every change; returns how to stop hearing them. */
33
+ fun watch(listener: (visible: Boolean) -> Unit): () -> Unit {
34
+ install()
35
+ listeners.add(listener)
36
+ return { listeners.remove(listener) }
37
+ }
38
+
39
+ /** Start following the process lifecycle (once; the work is posted to the main looper). */
40
+ fun install() {
41
+ if (!installed.compareAndSet(false, true)) return
42
+ val main = Handler(Looper.getMainLooper())
43
+ main.post {
44
+ try {
45
+ val lifecycle = ProcessLifecycleOwner.get().lifecycle
46
+ // INITIALIZED: the process lifecycle never started in this process (a
47
+ // second process, or an app that removed its initializer). Not knowing
48
+ // counts as visible, as below; a later start still reports changes.
49
+ if (lifecycle.currentState != Lifecycle.State.INITIALIZED) {
50
+ set(lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED))
51
+ }
52
+ lifecycle.addObserver(object : DefaultLifecycleObserver {
53
+ override fun onStart(owner: LifecycleOwner) = set(true)
54
+ override fun onStop(owner: LifecycleOwner) = set(false)
55
+ })
56
+ } catch (_: Throwable) {
57
+ // No process lifecycle (a test runner without it): treat the app as visible.
58
+ }
59
+ }
60
+ }
61
+
62
+ private fun set(now: Boolean) {
63
+ if (visible == now) return
64
+ visible = now
65
+ listeners.forEach { runCatching { it(now) } }
66
+ }
67
+ }
@@ -0,0 +1,67 @@
1
+ package com.voltkit.rtc.reactnative
2
+
3
+ /** What a [MediaDevice] is. Names as in every VoltKit SDK (`MediaDeviceInfo.kind`). */
4
+ @Suppress("EnumEntryName")
5
+ internal enum class DeviceKind {
6
+ audioinput,
7
+ videoinput,
8
+ audiooutput,
9
+ }
10
+
11
+ /** The kind of audio device, for an icon in a "speaker / phone / headset" picker. The Android SDK's names. */
12
+ @Suppress("EnumEntryName")
13
+ internal enum class AudioDeviceType {
14
+ /** The loudspeaker. */
15
+ speaker,
16
+
17
+ /** The phone's earpiece, held to the ear. Phones only; tablets and the emulator have none. */
18
+ earpiece,
19
+
20
+ /** Headphones or a headset on the jack. */
21
+ wiredHeadset,
22
+
23
+ /** A Bluetooth headset, car kit or hearing device, in call (two-way) mode. */
24
+ bluetooth,
25
+
26
+ /** A USB headset or audio interface. */
27
+ usb,
28
+
29
+ /** The device's own microphone. */
30
+ builtinMic,
31
+ other,
32
+ }
33
+
34
+ /**
35
+ * An audio input or output as [AudioRouter] lists it, the Android SDK's `MediaDevice` (Devices.kt) without cameras:
36
+ * react-native-webrtc lists those. JavaScript receives it as the client's `MediaDevice`.
37
+ */
38
+ internal data class MediaDevice(
39
+ /** Stable while the device stays connected: `speaker`, `earpiece`, `bluetooth:12`, `mic`. */
40
+ val deviceId: String,
41
+ val kind: DeviceKind,
42
+ /** A name to show, e.g. "Speaker", "Pixel Buds". */
43
+ val label: String,
44
+ val type: AudioDeviceType? = null,
45
+ /** Devices that belong together (a headset's microphone and earphones share one). */
46
+ val groupId: String = "",
47
+ )
48
+
49
+ /** The devices now, and what appeared and went since the last list (a headset plugged in, Bluetooth connected). */
50
+ internal data class DevicesChanged(
51
+ val devices: List<MediaDevice>,
52
+ val added: List<MediaDevice>,
53
+ val removed: List<MediaDevice>,
54
+ ) {
55
+ companion object {
56
+ /** What appeared and what went between two lists. */
57
+ fun between(before: List<MediaDevice>, after: List<MediaDevice>): DevicesChanged {
58
+ val was = before.map { it.kind to it.deviceId }.toSet()
59
+ val now = after.map { it.kind to it.deviceId }.toSet()
60
+ return DevicesChanged(
61
+ devices = after,
62
+ added = after.filter { (it.kind to it.deviceId) !in was },
63
+ removed = before.filter { (it.kind to it.deviceId) !in now },
64
+ )
65
+ }
66
+ }
67
+ }