@stream-io/video-react-native-sdk 1.21.2 → 1.22.1-alpha.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 (219) hide show
  1. package/android/gradle.properties +3 -3
  2. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +10 -0
  3. package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativePackage.kt +2 -1
  4. package/android/src/main/java/com/streamvideo/reactnative/audio/AudioDeviceManager.kt +592 -0
  5. package/android/src/main/java/com/streamvideo/reactnative/audio/BluetoothManager.kt +755 -0
  6. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioDeviceEndpointUtils.kt +192 -0
  7. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioFocusUtil.kt +62 -0
  8. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioManagerUtil.kt +159 -0
  9. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioSetupStoreUtil.kt +41 -0
  10. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +250 -0
  11. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +191 -0
  12. package/android/src/main/java/com/streamvideo/reactnative/model/AudioDeviceEndpoint.kt +136 -0
  13. package/android/src/main/java/org/webrtc/audio/WebRtcAudioTrackHelper.kt +12 -0
  14. package/dist/commonjs/components/Call/CallContent/CallContent.js +13 -9
  15. package/dist/commonjs/components/Call/CallContent/CallContent.js.map +1 -1
  16. package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js +9 -2
  17. package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
  18. package/dist/commonjs/components/Call/CallContent/RTCViewPipNative.js +3 -0
  19. package/dist/commonjs/components/Call/CallContent/RTCViewPipNative.js.map +1 -1
  20. package/dist/commonjs/components/Livestream/HostLivestream/HostLivestream.js +10 -6
  21. package/dist/commonjs/components/Livestream/HostLivestream/HostLivestream.js.map +1 -1
  22. package/dist/commonjs/components/Livestream/LivestreamControls/ViewerLivestreamControls.js +8 -4
  23. package/dist/commonjs/components/Livestream/LivestreamControls/ViewerLivestreamControls.js.map +1 -1
  24. package/dist/commonjs/components/Livestream/LivestreamLayout/LivestreamLayout.js +26 -27
  25. package/dist/commonjs/components/Livestream/LivestreamLayout/LivestreamLayout.js.map +1 -1
  26. package/dist/commonjs/components/Livestream/ViewerLivestream/ViewerLivestream.js +10 -6
  27. package/dist/commonjs/components/Livestream/ViewerLivestream/ViewerLivestream.js.map +1 -1
  28. package/dist/commonjs/hooks/useIsInPiPMode.js +3 -3
  29. package/dist/commonjs/hooks/useIsInPiPMode.js.map +1 -1
  30. package/dist/commonjs/hooks/usePermissionNotification.js +5 -5
  31. package/dist/commonjs/hooks/usePermissionNotification.js.map +1 -1
  32. package/dist/commonjs/index.js +12 -0
  33. package/dist/commonjs/index.js.map +1 -1
  34. package/dist/commonjs/modules/call-manager/CallManager.js +113 -0
  35. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -0
  36. package/dist/commonjs/modules/call-manager/PrevLibDetection.js +18 -0
  37. package/dist/commonjs/modules/call-manager/PrevLibDetection.js.map +1 -0
  38. package/dist/commonjs/modules/call-manager/index.js +24 -0
  39. package/dist/commonjs/modules/call-manager/index.js.map +1 -0
  40. package/dist/commonjs/modules/call-manager/native-module.d.js +4 -0
  41. package/dist/commonjs/modules/call-manager/native-module.d.js.map +1 -0
  42. package/dist/commonjs/modules/call-manager/types.js +2 -0
  43. package/dist/commonjs/modules/call-manager/types.js.map +1 -0
  44. package/dist/commonjs/providers/StreamCall/AppStateListener.js +5 -5
  45. package/dist/commonjs/providers/StreamCall/AppStateListener.js.map +1 -1
  46. package/dist/commonjs/theme/theme.js.map +1 -1
  47. package/dist/commonjs/utils/internal/rxSubjects.js +2 -2
  48. package/dist/commonjs/utils/internal/rxSubjects.js.map +1 -1
  49. package/dist/commonjs/version.js +1 -1
  50. package/dist/commonjs/version.js.map +1 -1
  51. package/dist/module/components/Call/CallContent/CallContent.js +14 -9
  52. package/dist/module/components/Call/CallContent/CallContent.js.map +1 -1
  53. package/dist/module/components/Call/CallContent/RTCViewPipIOS.js +9 -2
  54. package/dist/module/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
  55. package/dist/module/components/Call/CallContent/RTCViewPipNative.js +3 -0
  56. package/dist/module/components/Call/CallContent/RTCViewPipNative.js.map +1 -1
  57. package/dist/module/components/Livestream/HostLivestream/HostLivestream.js +10 -5
  58. package/dist/module/components/Livestream/HostLivestream/HostLivestream.js.map +1 -1
  59. package/dist/module/components/Livestream/LivestreamControls/ViewerLivestreamControls.js +9 -4
  60. package/dist/module/components/Livestream/LivestreamControls/ViewerLivestreamControls.js.map +1 -1
  61. package/dist/module/components/Livestream/LivestreamLayout/LivestreamLayout.js +26 -27
  62. package/dist/module/components/Livestream/LivestreamLayout/LivestreamLayout.js.map +1 -1
  63. package/dist/module/components/Livestream/ViewerLivestream/ViewerLivestream.js +10 -5
  64. package/dist/module/components/Livestream/ViewerLivestream/ViewerLivestream.js.map +1 -1
  65. package/dist/module/hooks/useIsInPiPMode.js +4 -4
  66. package/dist/module/hooks/useIsInPiPMode.js.map +1 -1
  67. package/dist/module/hooks/usePermissionNotification.js +7 -6
  68. package/dist/module/hooks/usePermissionNotification.js.map +1 -1
  69. package/dist/module/icons/Back.js +1 -1
  70. package/dist/module/icons/Back.js.map +1 -1
  71. package/dist/module/icons/CameraSwitch.js +1 -1
  72. package/dist/module/icons/CameraSwitch.js.map +1 -1
  73. package/dist/module/icons/Mic.js +1 -1
  74. package/dist/module/icons/Mic.js.map +1 -1
  75. package/dist/module/icons/MicOff.js +1 -1
  76. package/dist/module/icons/MicOff.js.map +1 -1
  77. package/dist/module/icons/Phone.js +1 -1
  78. package/dist/module/icons/Phone.js.map +1 -1
  79. package/dist/module/icons/PinVertical.js +1 -1
  80. package/dist/module/icons/PinVertical.js.map +1 -1
  81. package/dist/module/icons/Reaction.js +1 -1
  82. package/dist/module/icons/Reaction.js.map +1 -1
  83. package/dist/module/icons/Spotlight.js +1 -1
  84. package/dist/module/icons/Spotlight.js.map +1 -1
  85. package/dist/module/icons/Video.js +1 -1
  86. package/dist/module/icons/Video.js.map +1 -1
  87. package/dist/module/icons/VideoSlash.js +1 -1
  88. package/dist/module/icons/VideoSlash.js.map +1 -1
  89. package/dist/module/index.js +1 -0
  90. package/dist/module/index.js.map +1 -1
  91. package/dist/module/modules/call-manager/CallManager.js +106 -0
  92. package/dist/module/modules/call-manager/CallManager.js.map +1 -0
  93. package/dist/module/modules/call-manager/PrevLibDetection.js +12 -0
  94. package/dist/module/modules/call-manager/PrevLibDetection.js.map +1 -0
  95. package/dist/module/modules/call-manager/index.js +4 -0
  96. package/dist/module/modules/call-manager/index.js.map +1 -0
  97. package/dist/module/modules/call-manager/native-module.d.js +2 -0
  98. package/dist/module/modules/call-manager/native-module.d.js.map +1 -0
  99. package/dist/module/modules/call-manager/types.js +2 -0
  100. package/dist/module/modules/call-manager/types.js.map +1 -0
  101. package/dist/module/providers/StreamCall/AppStateListener.js +6 -6
  102. package/dist/module/providers/StreamCall/AppStateListener.js.map +1 -1
  103. package/dist/module/theme/theme.js.map +1 -1
  104. package/dist/module/utils/internal/rxSubjects.js +1 -1
  105. package/dist/module/utils/internal/rxSubjects.js.map +1 -1
  106. package/dist/module/version.js +1 -1
  107. package/dist/module/version.js.map +1 -1
  108. package/dist/typescript/components/Call/CallContent/CallContent.d.ts +3 -2
  109. package/dist/typescript/components/Call/CallContent/CallContent.d.ts.map +1 -1
  110. package/dist/typescript/components/Call/CallContent/RTCViewPipIOS.d.ts +5 -0
  111. package/dist/typescript/components/Call/CallContent/RTCViewPipIOS.d.ts.map +1 -1
  112. package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts +6 -0
  113. package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts.map +1 -1
  114. package/dist/typescript/components/Livestream/HostLivestream/HostLivestream.d.ts.map +1 -1
  115. package/dist/typescript/components/Livestream/LivestreamControls/ViewerLivestreamControls.d.ts.map +1 -1
  116. package/dist/typescript/components/Livestream/LivestreamLayout/LivestreamLayout.d.ts.map +1 -1
  117. package/dist/typescript/components/Livestream/ViewerLivestream/ViewerLivestream.d.ts.map +1 -1
  118. package/dist/typescript/hooks/usePermissionNotification.d.ts.map +1 -1
  119. package/dist/typescript/icons/Back.d.ts +1 -1
  120. package/dist/typescript/icons/Back.d.ts.map +1 -1
  121. package/dist/typescript/icons/BadNetwork.d.ts +1 -1
  122. package/dist/typescript/icons/BadNetwork.d.ts.map +1 -1
  123. package/dist/typescript/icons/CameraSwitch.d.ts +1 -1
  124. package/dist/typescript/icons/CameraSwitch.d.ts.map +1 -1
  125. package/dist/typescript/icons/LivestreamControls.d.ts +1 -1
  126. package/dist/typescript/icons/LivestreamControls.d.ts.map +1 -1
  127. package/dist/typescript/icons/Lock.d.ts +1 -1
  128. package/dist/typescript/icons/Lock.d.ts.map +1 -1
  129. package/dist/typescript/icons/Maximize.d.ts +1 -1
  130. package/dist/typescript/icons/Maximize.d.ts.map +1 -1
  131. package/dist/typescript/icons/Mic.d.ts +1 -1
  132. package/dist/typescript/icons/Mic.d.ts.map +1 -1
  133. package/dist/typescript/icons/MicOff.d.ts +1 -1
  134. package/dist/typescript/icons/MicOff.d.ts.map +1 -1
  135. package/dist/typescript/icons/Phone.d.ts +1 -1
  136. package/dist/typescript/icons/Phone.d.ts.map +1 -1
  137. package/dist/typescript/icons/PhoneDown.d.ts +1 -1
  138. package/dist/typescript/icons/PhoneDown.d.ts.map +1 -1
  139. package/dist/typescript/icons/PinVertical.d.ts +1 -1
  140. package/dist/typescript/icons/PinVertical.d.ts.map +1 -1
  141. package/dist/typescript/icons/Reaction.d.ts +1 -1
  142. package/dist/typescript/icons/Reaction.d.ts.map +1 -1
  143. package/dist/typescript/icons/ScreenShare.d.ts +1 -1
  144. package/dist/typescript/icons/ScreenShare.d.ts.map +1 -1
  145. package/dist/typescript/icons/ScreenShareIndicator.d.ts +1 -1
  146. package/dist/typescript/icons/ScreenShareIndicator.d.ts.map +1 -1
  147. package/dist/typescript/icons/Spotlight.d.ts +1 -1
  148. package/dist/typescript/icons/Spotlight.d.ts.map +1 -1
  149. package/dist/typescript/icons/StopScreenShare.d.ts +1 -1
  150. package/dist/typescript/icons/StopScreenShare.d.ts.map +1 -1
  151. package/dist/typescript/icons/Video.d.ts +1 -1
  152. package/dist/typescript/icons/Video.d.ts.map +1 -1
  153. package/dist/typescript/icons/VideoSlash.d.ts +1 -1
  154. package/dist/typescript/icons/VideoSlash.d.ts.map +1 -1
  155. package/dist/typescript/index.d.ts +1 -0
  156. package/dist/typescript/index.d.ts.map +1 -1
  157. package/dist/typescript/modules/call-manager/CallManager.d.ts +67 -0
  158. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -0
  159. package/dist/typescript/modules/call-manager/PrevLibDetection.d.ts +13 -0
  160. package/dist/typescript/modules/call-manager/PrevLibDetection.d.ts.map +1 -0
  161. package/dist/typescript/modules/call-manager/index.d.ts +4 -0
  162. package/dist/typescript/modules/call-manager/index.d.ts.map +1 -0
  163. package/dist/typescript/modules/call-manager/types.d.ts +15 -0
  164. package/dist/typescript/modules/call-manager/types.d.ts.map +1 -0
  165. package/dist/typescript/providers/StreamCall/AppStateListener.d.ts.map +1 -1
  166. package/dist/typescript/theme/theme.d.ts +1 -2
  167. package/dist/typescript/theme/theme.d.ts.map +1 -1
  168. package/dist/typescript/utils/internal/rxSubjects.d.ts +1 -1
  169. package/dist/typescript/utils/internal/rxSubjects.d.ts.map +1 -1
  170. package/dist/typescript/version.d.ts +1 -1
  171. package/dist/typescript/version.d.ts.map +1 -1
  172. package/ios/PictureInPicture/StreamPictureInPictureController.swift +5 -0
  173. package/ios/RTCViewPip.swift +15 -0
  174. package/ios/RTCViewPipManager.mm +1 -0
  175. package/ios/StreamInCallManager.m +26 -0
  176. package/ios/StreamInCallManager.swift +303 -0
  177. package/ios/StreamVideoReactNative-Bridging-Header.h +1 -0
  178. package/ios/StreamVideoReactNative.m +6 -5
  179. package/ios/StreamVideoReactNative.xcodeproj/project.xcworkspace/xcuserdata/santhoshvaiyapuri.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  180. package/ios/StreamVideoReactNative.xcodeproj/xcuserdata/santhoshvaiyapuri.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  181. package/package.json +33 -35
  182. package/src/components/Call/CallContent/CallContent.tsx +14 -10
  183. package/src/components/Call/CallContent/RTCViewPipIOS.tsx +17 -2
  184. package/src/components/Call/CallContent/RTCViewPipNative.tsx +8 -0
  185. package/src/components/Livestream/HostLivestream/HostLivestream.tsx +8 -3
  186. package/src/components/Livestream/LivestreamControls/ViewerLivestreamControls.tsx +11 -5
  187. package/src/components/Livestream/LivestreamLayout/LivestreamLayout.tsx +38 -29
  188. package/src/components/Livestream/ViewerLivestream/ViewerLivestream.tsx +8 -3
  189. package/src/hooks/useIsInPiPMode.tsx +4 -4
  190. package/src/hooks/usePermissionNotification.tsx +7 -12
  191. package/src/icons/Back.tsx +2 -2
  192. package/src/icons/BadNetwork.tsx +1 -1
  193. package/src/icons/CameraSwitch.tsx +2 -2
  194. package/src/icons/LivestreamControls.tsx +1 -1
  195. package/src/icons/Lock.tsx +1 -1
  196. package/src/icons/Maximize.tsx +1 -1
  197. package/src/icons/Mic.tsx +2 -2
  198. package/src/icons/MicOff.tsx +2 -2
  199. package/src/icons/Phone.tsx +2 -2
  200. package/src/icons/PhoneDown.tsx +1 -1
  201. package/src/icons/PinVertical.tsx +2 -2
  202. package/src/icons/Reaction.tsx +2 -2
  203. package/src/icons/ScreenShare.tsx +1 -1
  204. package/src/icons/ScreenShareIndicator.tsx +1 -1
  205. package/src/icons/Spotlight.tsx +2 -2
  206. package/src/icons/StopScreenShare.tsx +1 -1
  207. package/src/icons/Video.tsx +2 -2
  208. package/src/icons/VideoSlash.tsx +2 -2
  209. package/src/index.ts +1 -0
  210. package/src/modules/call-manager/CallManager.ts +116 -0
  211. package/src/modules/call-manager/PrevLibDetection.ts +27 -0
  212. package/src/modules/call-manager/index.ts +5 -0
  213. package/src/modules/call-manager/native-module.d.ts +80 -0
  214. package/src/modules/call-manager/types.ts +25 -0
  215. package/src/providers/StreamCall/AppStateListener.tsx +6 -9
  216. package/src/theme/theme.ts +2 -2
  217. package/src/utils/internal/rxSubjects.ts +1 -1
  218. package/src/version.ts +1 -1
  219. package/CHANGELOG.md +0 -2783
@@ -0,0 +1,192 @@
1
+ /*
2
+ * Copyright 2023 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ package com.streamvideo.reactnative.audio.utils
18
+
19
+ import android.media.AudioDeviceInfo
20
+ import android.util.Log
21
+ import com.streamvideo.reactnative.model.AudioDeviceEndpoint
22
+ import com.streamvideo.reactnative.model.AudioDeviceEndpoint.Companion.EndpointType
23
+
24
+ internal class AudioDeviceEndpointUtils {
25
+
26
+ companion object {
27
+ const val BLUETOOTH_DEVICE_DEFAULT_NAME = "Bluetooth Device"
28
+ const val EARPIECE = "Earpiece"
29
+ const val SPEAKER = "Speaker"
30
+ const val WIRED_HEADSET = "Wired Headset"
31
+ const val UNKNOWN = "Unknown"
32
+
33
+ private val TAG: String = AudioDeviceEndpointUtils::class.java.simpleName.toString()
34
+
35
+ /** Gets the endpoints from AudioDeviceInfos.
36
+ * IMPORTANT: eliminates Earpiece if Headset is found
37
+ * */
38
+ fun getEndpointsFromAudioDeviceInfo(
39
+ adiArr: List<AudioDeviceInfo>?,
40
+ ): List<AudioDeviceEndpoint> {
41
+ if (adiArr == null) {
42
+ return listOf()
43
+ }
44
+ val endpoints: MutableList<AudioDeviceEndpoint> = mutableListOf()
45
+ var foundWiredHeadset = false
46
+ val omittedDevices = StringBuilder("omitting devices =[")
47
+ adiArr.toList().forEach { audioDeviceInfo ->
48
+ val endpoint = getEndpointFromAudioDeviceInfo(audioDeviceInfo)
49
+ if (endpoint.type != AudioDeviceEndpoint.TYPE_UNKNOWN) {
50
+ if (endpoint.type == AudioDeviceEndpoint.TYPE_WIRED_HEADSET) {
51
+ foundWiredHeadset = true
52
+ }
53
+ endpoints.add(endpoint)
54
+ } else {
55
+ omittedDevices.append(
56
+ "(type=[${audioDeviceInfo.type}]," +
57
+ " name=[${audioDeviceInfo.productName}]),"
58
+ )
59
+ }
60
+ }
61
+ omittedDevices.append("]")
62
+ Log.i(TAG, omittedDevices.toString())
63
+ if (foundWiredHeadset) {
64
+ endpoints.removeIf { it.type == AudioDeviceEndpoint.TYPE_EARPIECE }
65
+ }
66
+ // Sort by endpoint type. The first element has the highest priority!
67
+ endpoints.sort()
68
+ return endpoints
69
+ }
70
+
71
+
72
+ private fun getEndpointFromAudioDeviceInfo(
73
+ adi: AudioDeviceInfo,
74
+ ): AudioDeviceEndpoint {
75
+ val endpointDeviceName = remapAudioDeviceNameToEndpointDeviceName(adi)
76
+ val endpointType = remapAudioDeviceTypeToCallEndpointType(adi.type)
77
+ val newEndpoint =
78
+ AudioDeviceEndpoint(
79
+ endpointDeviceName,
80
+ endpointType,
81
+ adi,
82
+ )
83
+ return newEndpoint
84
+ }
85
+
86
+ internal fun remapAudioDeviceNameToEndpointDeviceName(
87
+ audioDeviceInfo: AudioDeviceInfo,
88
+ ): String {
89
+ return when (audioDeviceInfo.type) {
90
+ AudioDeviceInfo.TYPE_BUILTIN_EARPIECE ->
91
+ EARPIECE
92
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER ->
93
+ SPEAKER
94
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
95
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
96
+ AudioDeviceInfo.TYPE_USB_DEVICE,
97
+ AudioDeviceInfo.TYPE_USB_ACCESSORY,
98
+ AudioDeviceInfo.TYPE_USB_HEADSET ->
99
+ WIRED_HEADSET
100
+ else -> audioDeviceInfo.productName.toString()
101
+ }
102
+ }
103
+
104
+ internal fun remapAudioDeviceTypeToCallEndpointType(
105
+ audioDeviceInfoType: Int
106
+ ): (@EndpointType Int) {
107
+ return when (audioDeviceInfoType) {
108
+ AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> AudioDeviceEndpoint.TYPE_EARPIECE
109
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> AudioDeviceEndpoint.TYPE_SPEAKER
110
+ // Wired Headset Devices
111
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
112
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
113
+ AudioDeviceInfo.TYPE_USB_DEVICE,
114
+ AudioDeviceInfo.TYPE_USB_ACCESSORY,
115
+ AudioDeviceInfo.TYPE_USB_HEADSET -> AudioDeviceEndpoint.TYPE_WIRED_HEADSET
116
+ // Bluetooth Devices
117
+ AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
118
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
119
+ AudioDeviceInfo.TYPE_HEARING_AID,
120
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
121
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
122
+ AudioDeviceInfo.TYPE_BLE_BROADCAST -> AudioDeviceEndpoint.TYPE_BLUETOOTH
123
+ // Everything else is defaulted to TYPE_UNKNOWN
124
+ else -> AudioDeviceEndpoint.TYPE_UNKNOWN
125
+ }
126
+ }
127
+
128
+ fun getSpeakerEndpoint(endpoints: List<AudioDeviceEndpoint>): AudioDeviceEndpoint? {
129
+ for (e in endpoints) {
130
+ if (e.type == AudioDeviceEndpoint.TYPE_SPEAKER) {
131
+ return e
132
+ }
133
+ }
134
+ return null
135
+ }
136
+
137
+ fun isBluetoothAvailable(endpoints: List<AudioDeviceEndpoint>): Boolean {
138
+ for (e in endpoints) {
139
+ if (e.type == AudioDeviceEndpoint.TYPE_BLUETOOTH) {
140
+ return true
141
+ }
142
+ }
143
+ return false
144
+ }
145
+
146
+ fun isEarpieceEndpoint(endpoint: AudioDeviceEndpoint?): Boolean {
147
+ if (endpoint == null) {
148
+ return false
149
+ }
150
+ return endpoint.type == AudioDeviceEndpoint.TYPE_EARPIECE
151
+ }
152
+
153
+ fun isSpeakerEndpoint(endpoint: AudioDeviceEndpoint?): Boolean {
154
+ if (endpoint == null) {
155
+ return false
156
+ }
157
+ return endpoint.type == AudioDeviceEndpoint.TYPE_SPEAKER
158
+ }
159
+
160
+ fun isWiredHeadsetOrBtEndpoint(endpoint: AudioDeviceEndpoint?): Boolean {
161
+ if (endpoint == null) {
162
+ return false
163
+ }
164
+ return endpoint.type == AudioDeviceEndpoint.TYPE_BLUETOOTH ||
165
+ endpoint.type == AudioDeviceEndpoint.TYPE_WIRED_HEADSET
166
+ }
167
+
168
+ private fun isBluetoothType(type: Int): Boolean {
169
+ return type == AudioDeviceEndpoint.TYPE_BLUETOOTH
170
+ }
171
+
172
+ fun endpointTypeToString(@EndpointType endpointType: Int): String {
173
+ return when (endpointType) {
174
+ AudioDeviceEndpoint.TYPE_EARPIECE -> EARPIECE
175
+ AudioDeviceEndpoint.TYPE_BLUETOOTH -> BLUETOOTH_DEVICE_DEFAULT_NAME
176
+ AudioDeviceEndpoint.TYPE_WIRED_HEADSET -> WIRED_HEADSET
177
+ AudioDeviceEndpoint.TYPE_SPEAKER -> SPEAKER
178
+ else -> UNKNOWN
179
+ }
180
+ }
181
+
182
+ fun endpointStringToType(endpointName: String): Int {
183
+ return when (endpointName) {
184
+ EARPIECE -> AudioDeviceEndpoint.TYPE_EARPIECE
185
+ WIRED_HEADSET -> AudioDeviceEndpoint.TYPE_WIRED_HEADSET
186
+ SPEAKER -> AudioDeviceEndpoint.TYPE_SPEAKER
187
+ BLUETOOTH_DEVICE_DEFAULT_NAME -> AudioDeviceEndpoint.TYPE_BLUETOOTH
188
+ else -> AudioDeviceEndpoint.TYPE_UNKNOWN
189
+ }
190
+ }
191
+ }
192
+ }
@@ -0,0 +1,62 @@
1
+ package com.streamvideo.reactnative.audio.utils
2
+
3
+ import android.media.AudioAttributes
4
+ import android.media.AudioFocusRequest
5
+ import android.media.AudioManager
6
+ import android.os.Build
7
+ import com.facebook.react.bridge.ReactContext
8
+ import com.oney.WebRTCModule.WebRTCModule
9
+ import org.webrtc.audio.JavaAudioDeviceModule
10
+ import org.webrtc.audio.WebRtcAudioTrackHelper
11
+
12
+ enum class CallAudioRole {
13
+ /* high quality audio output is prioritised */
14
+ Listener,
15
+
16
+ /* low latency audio output is prioritised */
17
+ Communicator
18
+ }
19
+
20
+ class AudioFocusUtil(
21
+ private val audioManager: AudioManager,
22
+ private val audioFocusChangeListener: AudioManager.OnAudioFocusChangeListener,
23
+ ) {
24
+
25
+ private lateinit var request: AudioFocusRequest
26
+
27
+
28
+
29
+ fun requestFocus(mode: CallAudioRole, reactContext: ReactContext) {
30
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
31
+ val audioAttributes = AudioAttributes.Builder()
32
+ .setUsage(if (mode == CallAudioRole.Communicator) AudioAttributes.USAGE_VOICE_COMMUNICATION else AudioAttributes.USAGE_MEDIA)
33
+ .setContentType(if (mode == CallAudioRole.Communicator) AudioAttributes.CONTENT_TYPE_SPEECH else AudioAttributes.CONTENT_TYPE_MUSIC)
34
+ .build()
35
+
36
+ // 1. set audio attributes to webrtc
37
+ val webRTCModule = reactContext.getNativeModule(WebRTCModule::class.java)!!
38
+ val adm = webRTCModule.audioDeviceModule as JavaAudioDeviceModule
39
+ WebRtcAudioTrackHelper.setAudioOutputAttributes(adm, audioAttributes)
40
+
41
+ // 2. request the audio focus with the audio attributes
42
+ request = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
43
+ .setAudioAttributes(audioAttributes).setAcceptsDelayedFocusGain(true)
44
+ .setOnAudioFocusChangeListener(audioFocusChangeListener).build()
45
+ audioManager.requestAudioFocus(request)
46
+ } else {
47
+ audioManager.requestAudioFocus(
48
+ audioFocusChangeListener,
49
+ if (mode == CallAudioRole.Communicator) AudioManager.STREAM_VOICE_CALL else AudioManager.STREAM_MUSIC,
50
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
51
+ )
52
+ }
53
+ }
54
+
55
+ fun abandonFocus() {
56
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
57
+ audioManager.abandonAudioFocusRequest(request)
58
+ } else {
59
+ audioManager.abandonAudioFocus(audioFocusChangeListener)
60
+ }
61
+ }
62
+ }
@@ -0,0 +1,159 @@
1
+ package com.streamvideo.reactnative.audio.utils
2
+
3
+ import android.media.AudioDeviceInfo
4
+ import android.media.AudioManager
5
+ import android.os.Build
6
+ import android.util.Log
7
+ import androidx.annotation.DoNotInline
8
+ import androidx.annotation.RequiresApi
9
+ import com.streamvideo.reactnative.audio.BluetoothManager
10
+ import com.streamvideo.reactnative.audio.EndpointMaps
11
+ import com.streamvideo.reactnative.callmanager.StreamInCallManagerModule
12
+ import com.streamvideo.reactnative.model.AudioDeviceEndpoint
13
+ import com.streamvideo.reactnative.model.AudioDeviceEndpoint.Companion.EndpointType
14
+
15
+
16
+ internal class AudioManagerUtil {
17
+ companion object {
18
+ private val TAG: String = StreamInCallManagerModule.TAG + ":" + AudioManagerUtil::class.java.simpleName.toString()
19
+
20
+ fun getAvailableAudioDevices(audioManager: AudioManager): List<AudioDeviceInfo> {
21
+ return if (Build.VERSION.SDK_INT >= 31) {
22
+ AudioManager31PlusImpl.getDevices(audioManager)
23
+ } else {
24
+ AudioManager23PlusImpl.getDevices(audioManager)
25
+ }
26
+ }
27
+
28
+ fun isSpeakerphoneOn(audioManager: AudioManager): Boolean {
29
+ return if (Build.VERSION.SDK_INT >= 31) {
30
+ AudioManager31PlusImpl.isSpeakerphoneOn(audioManager)
31
+ } else {
32
+ AudioManager23PlusImpl.isSpeakerphoneOn(audioManager)
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Switch the device endpoint type.
38
+ * @return true if the device endpoint type is successfully switched.
39
+ */
40
+ fun switchDeviceEndpointType(@EndpointType deviceType: Int,
41
+ endpointMaps: EndpointMaps,
42
+ audioManager: AudioManager,
43
+ bluetoothManager: BluetoothManager): AudioDeviceEndpoint? {
44
+ return if (Build.VERSION.SDK_INT >= 31) {
45
+ AudioManager31PlusImpl.switchDeviceEndpointType(deviceType, endpointMaps, audioManager, bluetoothManager)
46
+ } else {
47
+ AudioManager23PlusImpl.switchDeviceEndpointType(deviceType, endpointMaps, audioManager, bluetoothManager)
48
+ }
49
+ }
50
+ }
51
+
52
+ @RequiresApi(31)
53
+ object AudioManager31PlusImpl {
54
+ @JvmStatic
55
+ @DoNotInline
56
+ fun getDevices(audioManager: AudioManager): List<AudioDeviceInfo> {
57
+ return audioManager.availableCommunicationDevices
58
+ }
59
+
60
+ @JvmStatic
61
+ @DoNotInline
62
+ fun isSpeakerphoneOn(audioManager: AudioManager): Boolean {
63
+ val endpoint = AudioDeviceEndpointUtils.remapAudioDeviceTypeToCallEndpointType(audioManager.communicationDevice?.type ?: AudioDeviceInfo.TYPE_UNKNOWN)
64
+ return endpoint == AudioDeviceEndpoint.TYPE_SPEAKER
65
+ }
66
+
67
+ @JvmStatic
68
+ @DoNotInline
69
+ fun switchDeviceEndpointType(@EndpointType deviceType: Int,
70
+ endpointMaps: EndpointMaps,
71
+ audioManager: AudioManager,
72
+ bluetoothManager: BluetoothManager): AudioDeviceEndpoint? {
73
+ audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
74
+ when (deviceType) {
75
+ AudioDeviceEndpoint.TYPE_BLUETOOTH -> {
76
+ val didSwitch = bluetoothManager.startScoAudio()
77
+ if (didSwitch) {
78
+ return endpointMaps.bluetoothEndpoints[bluetoothManager.getDeviceName()]
79
+ }
80
+ return null
81
+ }
82
+ AudioDeviceEndpoint.TYPE_WIRED_HEADSET, AudioDeviceEndpoint.TYPE_EARPIECE -> {
83
+ endpointMaps.nonBluetoothEndpoints.values.firstOrNull {
84
+ it.type == deviceType
85
+ }?.let {
86
+ audioManager.setCommunicationDevice(it.deviceInfo)
87
+ bluetoothManager.updateDevice()
88
+ return endpointMaps.nonBluetoothEndpoints[deviceType]
89
+ }
90
+ return null
91
+ }
92
+ AudioDeviceEndpoint.TYPE_SPEAKER -> {
93
+ val speakerDevice = endpointMaps.nonBluetoothEndpoints[AudioDeviceEndpoint.TYPE_SPEAKER]
94
+ speakerDevice?.let {
95
+ audioManager.setCommunicationDevice(it.deviceInfo)
96
+ bluetoothManager.updateDevice()
97
+ return speakerDevice
98
+ }
99
+ return null
100
+ }
101
+ else -> {
102
+ Log.e(TAG, "switchDeviceEndpointType(): unknown device type requested")
103
+ return null
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ @Suppress("DEPRECATION")
110
+ object AudioManager23PlusImpl {
111
+ @JvmStatic
112
+ @DoNotInline
113
+ fun getDevices(audioManager: AudioManager): List<AudioDeviceInfo> {
114
+ return audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS).toList()
115
+ }
116
+
117
+ @JvmStatic
118
+ @DoNotInline
119
+ fun isSpeakerphoneOn(audioManager: AudioManager): Boolean {
120
+ return audioManager.isSpeakerphoneOn
121
+ }
122
+
123
+ @JvmStatic
124
+ @DoNotInline
125
+ fun switchDeviceEndpointType(@EndpointType deviceType: Int,
126
+ endpointMaps: EndpointMaps,
127
+ audioManager: AudioManager,
128
+ bluetoothManager: BluetoothManager): AudioDeviceEndpoint? {
129
+ audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
130
+ when (deviceType) {
131
+ AudioDeviceEndpoint.TYPE_BLUETOOTH -> {
132
+ audioManager.setSpeakerphoneOn(false)
133
+ val didSwitch = bluetoothManager.startScoAudio()
134
+ if (didSwitch) {
135
+ // NOTE: SCO connection may fail after timeout, how to catch that on older platforms?
136
+ return endpointMaps.bluetoothEndpoints[bluetoothManager.getDeviceName()]
137
+ }
138
+ return null
139
+ }
140
+ AudioDeviceEndpoint.TYPE_WIRED_HEADSET, AudioDeviceEndpoint.TYPE_EARPIECE -> {
141
+ // NOTE: If wired headset is present,
142
+ // earpiece is always omitted even if chosen
143
+ bluetoothManager.stopScoAudio()
144
+ audioManager.setSpeakerphoneOn(false)
145
+ return endpointMaps.nonBluetoothEndpoints[deviceType]
146
+ }
147
+ AudioDeviceEndpoint.TYPE_SPEAKER -> {
148
+ bluetoothManager.stopScoAudio()
149
+ audioManager.setSpeakerphoneOn(true)
150
+ return endpointMaps.nonBluetoothEndpoints[AudioDeviceEndpoint.TYPE_SPEAKER]
151
+ }
152
+ else -> {
153
+ Log.e(TAG, "switchDeviceEndpointType(): unknown device type requested")
154
+ return null
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
@@ -0,0 +1,41 @@
1
+ package com.streamvideo.reactnative.audio.utils
2
+
3
+ import android.media.AudioManager
4
+ import android.util.Log
5
+ import com.facebook.react.bridge.ReactContext
6
+ import com.streamvideo.reactnative.audio.AudioDeviceManager
7
+ import com.streamvideo.reactnative.callmanager.StreamInCallManagerModule.Companion.TAG
8
+
9
+ class AudioSetupStoreUtil(
10
+ private val mReactContext: ReactContext,
11
+ private val mAudioManager: AudioManager,
12
+ private val mAudioDeviceManager: AudioDeviceManager
13
+ ) {
14
+ private var isOrigAudioSetupStored = false
15
+ private var origIsSpeakerPhoneOn = false
16
+ private var origIsMicrophoneMute = false
17
+ private var origAudioMode = AudioManager.MODE_NORMAL
18
+
19
+ fun storeOriginalAudioSetup() {
20
+ if (!isOrigAudioSetupStored) {
21
+ origAudioMode = mAudioManager.mode
22
+ origIsSpeakerPhoneOn = AudioManagerUtil.isSpeakerphoneOn(mAudioManager)
23
+ origIsMicrophoneMute = mAudioManager.isMicrophoneMute
24
+ isOrigAudioSetupStored = true
25
+ }
26
+ }
27
+
28
+ fun restoreOriginalAudioSetup() {
29
+ if (isOrigAudioSetupStored) {
30
+ if (origIsSpeakerPhoneOn) {
31
+ mAudioDeviceManager.setSpeakerphoneOn(true)
32
+ }
33
+ mAudioManager.setMicrophoneMute(origIsMicrophoneMute)
34
+ mAudioManager.mode = origAudioMode
35
+ mReactContext.currentActivity?.apply {
36
+ volumeControlStream = AudioManager.USE_DEFAULT_STREAM_TYPE
37
+ }
38
+ isOrigAudioSetupStored = false
39
+ }
40
+ }
41
+ }