@sbhjt-gr/react-native-webrtc 124.0.3 → 124.0.4

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 (361) hide show
  1. package/.clang-format +11 -11
  2. package/.eslintignore +6 -6
  3. package/.nvmrc +1 -1
  4. package/ISSUE_TEMPLATE.md +40 -40
  5. package/LICENSE +22 -22
  6. package/README.md +103 -103
  7. package/android/build.gradle +37 -37
  8. package/android/consumer-rules.pro +3 -3
  9. package/android/src/main/AndroidManifest.xml +11 -11
  10. package/android/src/main/java/com/oney/WebRTCModule/AbstractVideoCaptureController.java +113 -113
  11. package/android/src/main/java/com/oney/WebRTCModule/CameraCaptureController.java +338 -338
  12. package/android/src/main/java/com/oney/WebRTCModule/CameraEventsHandler.java +49 -49
  13. package/android/src/main/java/com/oney/WebRTCModule/DataChannelWrapper.java +99 -99
  14. package/android/src/main/java/com/oney/WebRTCModule/DataPacketCryptorManager.java +62 -62
  15. package/android/src/main/java/com/oney/WebRTCModule/DisplayUtils.java +16 -16
  16. package/android/src/main/java/com/oney/WebRTCModule/EglUtils.java +66 -66
  17. package/android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java +539 -539
  18. package/android/src/main/java/com/oney/WebRTCModule/LibraryLoader.java +21 -21
  19. package/android/src/main/java/com/oney/WebRTCModule/MediaProjectionNotification.java +70 -70
  20. package/android/src/main/java/com/oney/WebRTCModule/MediaProjectionService.java +82 -82
  21. package/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java +588 -588
  22. package/android/src/main/java/com/oney/WebRTCModule/RTCCryptoManager.java +493 -493
  23. package/android/src/main/java/com/oney/WebRTCModule/RTCVideoViewManager.java +98 -98
  24. package/android/src/main/java/com/oney/WebRTCModule/ReactBridgeUtil.java +35 -35
  25. package/android/src/main/java/com/oney/WebRTCModule/ScreenCaptureController.java +94 -94
  26. package/android/src/main/java/com/oney/WebRTCModule/SerializeUtils.java +342 -342
  27. package/android/src/main/java/com/oney/WebRTCModule/StringUtils.java +100 -100
  28. package/android/src/main/java/com/oney/WebRTCModule/ThreadUtils.java +41 -41
  29. package/android/src/main/java/com/oney/WebRTCModule/TrackCapturerEventsEmitter.java +34 -34
  30. package/android/src/main/java/com/oney/WebRTCModule/VideoTrackAdapter.java +137 -137
  31. package/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java +1649 -1643
  32. package/android/src/main/java/com/oney/WebRTCModule/WebRTCModuleOptions.java +33 -33
  33. package/android/src/main/java/com/oney/WebRTCModule/WebRTCModulePackage.java +21 -21
  34. package/android/src/main/java/com/oney/WebRTCModule/WebRTCView.java +583 -583
  35. package/android/src/main/java/com/oney/WebRTCModule/palabra/PalabraClient.java +529 -501
  36. package/android/src/main/java/com/oney/WebRTCModule/palabra/PalabraConfig.java +17 -17
  37. package/android/src/main/java/com/oney/WebRTCModule/palabra/PalabraListener.java +7 -7
  38. package/android/src/main/java/com/oney/WebRTCModule/videoEffects/ProcessorProvider.java +38 -38
  39. package/android/src/main/java/com/oney/WebRTCModule/videoEffects/VideoEffectProcessor.java +59 -59
  40. package/android/src/main/java/com/oney/WebRTCModule/videoEffects/VideoFrameProcessor.java +19 -19
  41. package/android/src/main/java/com/oney/WebRTCModule/videoEffects/VideoFrameProcessorFactoryInterface.java +12 -12
  42. package/android/src/main/java/com/oney/WebRTCModule/webrtcutils/H264AndSoftwareVideoDecoderFactory.java +73 -73
  43. package/android/src/main/java/com/oney/WebRTCModule/webrtcutils/H264AndSoftwareVideoEncoderFactory.java +73 -73
  44. package/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SoftwareVideoDecoderFactoryProxy.java +36 -36
  45. package/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SoftwareVideoEncoderFactoryProxy.java +36 -36
  46. package/android/src/main/java/org/webrtc/Camera1Helper.java +54 -54
  47. package/android/src/main/java/org/webrtc/Camera2Helper.java +52 -52
  48. package/android/src/main/res/values/strings.xml +5 -5
  49. package/android/src/main/res/values/styles.xml +8 -8
  50. package/ios/RCTWebRTC/CaptureController.h +18 -18
  51. package/ios/RCTWebRTC/CaptureController.m +28 -28
  52. package/ios/RCTWebRTC/CapturerEventsDelegate.h +12 -12
  53. package/ios/RCTWebRTC/DataChannelWrapper.h +27 -27
  54. package/ios/RCTWebRTC/DataChannelWrapper.m +42 -42
  55. package/ios/RCTWebRTC/I420Converter.h +22 -22
  56. package/ios/RCTWebRTC/I420Converter.m +164 -164
  57. package/ios/RCTWebRTC/PIPController.h +24 -24
  58. package/ios/RCTWebRTC/PIPController.m +234 -234
  59. package/ios/RCTWebRTC/PalabraAudioSink.h +13 -13
  60. package/ios/RCTWebRTC/PalabraAudioSink.m +18 -18
  61. package/ios/RCTWebRTC/PalabraClient.h +42 -36
  62. package/ios/RCTWebRTC/PalabraClient.m +680 -644
  63. package/ios/RCTWebRTC/RCTConvert+WebRTC.h +16 -16
  64. package/ios/RCTWebRTC/RCTConvert+WebRTC.m +206 -206
  65. package/ios/RCTWebRTC/RTCMediaStreamTrack+React.h +10 -10
  66. package/ios/RCTWebRTC/RTCMediaStreamTrack+React.m +16 -16
  67. package/ios/RCTWebRTC/RTCVideoViewManager.h +29 -29
  68. package/ios/RCTWebRTC/RTCVideoViewManager.m +411 -411
  69. package/ios/RCTWebRTC/SampleBufferVideoCallView.h +12 -12
  70. package/ios/RCTWebRTC/SampleBufferVideoCallView.m +178 -178
  71. package/ios/RCTWebRTC/ScreenCaptureController.h +20 -20
  72. package/ios/RCTWebRTC/ScreenCaptureController.m +82 -82
  73. package/ios/RCTWebRTC/ScreenCapturePickerViewManager.h +7 -7
  74. package/ios/RCTWebRTC/ScreenCapturePickerViewManager.m +59 -59
  75. package/ios/RCTWebRTC/ScreenCapturer.h +19 -19
  76. package/ios/RCTWebRTC/ScreenCapturer.m +263 -263
  77. package/ios/RCTWebRTC/SerializeUtils.h +28 -28
  78. package/ios/RCTWebRTC/SerializeUtils.m +314 -314
  79. package/ios/RCTWebRTC/SocketConnection.h +13 -13
  80. package/ios/RCTWebRTC/SocketConnection.m +137 -137
  81. package/ios/RCTWebRTC/TrackCapturerEventsEmitter.h +14 -14
  82. package/ios/RCTWebRTC/TrackCapturerEventsEmitter.m +36 -36
  83. package/ios/RCTWebRTC/VideoCaptureController.h +21 -21
  84. package/ios/RCTWebRTC/VideoCaptureController.m +328 -328
  85. package/ios/RCTWebRTC/WLVAudioDevice.h +12 -12
  86. package/ios/RCTWebRTC/WLVAudioDevice.m +137 -137
  87. package/ios/RCTWebRTC/WebRTCModule+Palabra.h +4 -4
  88. package/ios/RCTWebRTC/WebRTCModule+Palabra.m +92 -83
  89. package/ios/RCTWebRTC/WebRTCModule+Permissions.m +75 -75
  90. package/ios/RCTWebRTC/WebRTCModule+RTCAudioSession.m +20 -20
  91. package/ios/RCTWebRTC/WebRTCModule+RTCDataChannel.h +14 -14
  92. package/ios/RCTWebRTC/WebRTCModule+RTCDataChannel.m +165 -165
  93. package/ios/RCTWebRTC/WebRTCModule+RTCFrameCryptor.m +611 -611
  94. package/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.h +13 -13
  95. package/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m +728 -728
  96. package/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.h +24 -24
  97. package/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m +1004 -1004
  98. package/ios/RCTWebRTC/WebRTCModule+Transceivers.m +267 -267
  99. package/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h +12 -12
  100. package/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m +166 -166
  101. package/ios/RCTWebRTC/WebRTCModule.h +58 -58
  102. package/ios/RCTWebRTC/WebRTCModule.m +169 -169
  103. package/ios/RCTWebRTC/WebRTCModuleOptions.h +24 -24
  104. package/ios/RCTWebRTC/WebRTCModuleOptions.m +31 -31
  105. package/ios/RCTWebRTC/videoEffects/ProcessorProvider.h +9 -9
  106. package/ios/RCTWebRTC/videoEffects/ProcessorProvider.m +23 -23
  107. package/ios/RCTWebRTC/videoEffects/VideoEffectProcessor.h +13 -13
  108. package/ios/RCTWebRTC/videoEffects/VideoEffectProcessor.m +23 -23
  109. package/ios/RCTWebRTC/videoEffects/VideoFrameProcessor.h +8 -8
  110. package/ios/RCTWebRTC.xcodeproj/project.pbxproj +404 -404
  111. package/ios/RCTWebRTC.xcworkspace/contents.xcworkspacedata +10 -10
  112. package/lib/commonjs/Constraints.js.map +1 -1
  113. package/lib/commonjs/EventEmitter.js.map +1 -1
  114. package/lib/commonjs/Logger.js.map +1 -1
  115. package/lib/commonjs/MediaDevices.js +17 -17
  116. package/lib/commonjs/MediaDevices.js.map +1 -1
  117. package/lib/commonjs/MediaStream.js +19 -19
  118. package/lib/commonjs/MediaStream.js.map +1 -1
  119. package/lib/commonjs/MediaStreamError.js.map +1 -1
  120. package/lib/commonjs/MediaStreamErrorEvent.js.map +1 -1
  121. package/lib/commonjs/MediaStreamTrack.js +28 -28
  122. package/lib/commonjs/MediaStreamTrack.js.map +1 -1
  123. package/lib/commonjs/MediaStreamTrackEvent.js +6 -6
  124. package/lib/commonjs/MediaStreamTrackEvent.js.map +1 -1
  125. package/lib/commonjs/MessageEvent.js +7 -7
  126. package/lib/commonjs/MessageEvent.js.map +1 -1
  127. package/lib/commonjs/Permissions.js +28 -28
  128. package/lib/commonjs/Permissions.js.map +1 -1
  129. package/lib/commonjs/RTCAudioSession.js +4 -4
  130. package/lib/commonjs/RTCAudioSession.js.map +1 -1
  131. package/lib/commonjs/RTCDataChannel.js +2 -2
  132. package/lib/commonjs/RTCDataChannel.js.map +1 -1
  133. package/lib/commonjs/RTCDataChannelEvent.js +6 -6
  134. package/lib/commonjs/RTCDataChannelEvent.js.map +1 -1
  135. package/lib/commonjs/RTCDataPacketCryptor.js.map +1 -1
  136. package/lib/commonjs/RTCDataPacketCryptorFactory.js.map +1 -1
  137. package/lib/commonjs/RTCErrorEvent.js +3 -3
  138. package/lib/commonjs/RTCErrorEvent.js.map +1 -1
  139. package/lib/commonjs/RTCFrameCryptor.js +8 -8
  140. package/lib/commonjs/RTCFrameCryptor.js.map +1 -1
  141. package/lib/commonjs/RTCFrameCryptorFactory.js.map +1 -1
  142. package/lib/commonjs/RTCIceCandidate.js.map +1 -1
  143. package/lib/commonjs/RTCIceCandidateEvent.js +7 -7
  144. package/lib/commonjs/RTCIceCandidateEvent.js.map +1 -1
  145. package/lib/commonjs/RTCKeyProvider.js.map +1 -1
  146. package/lib/commonjs/RTCPIPView.js +2 -2
  147. package/lib/commonjs/RTCPIPView.js.map +1 -1
  148. package/lib/commonjs/RTCPIPView.web.js.map +1 -1
  149. package/lib/commonjs/RTCPeerConnection.js +36 -36
  150. package/lib/commonjs/RTCPeerConnection.js.map +1 -1
  151. package/lib/commonjs/RTCRtcpParameters.js.map +1 -1
  152. package/lib/commonjs/RTCRtpCapabilities.js +2 -2
  153. package/lib/commonjs/RTCRtpCapabilities.js.map +1 -1
  154. package/lib/commonjs/RTCRtpCodecCapability.js.map +1 -1
  155. package/lib/commonjs/RTCRtpCodecParameters.js.map +1 -1
  156. package/lib/commonjs/RTCRtpEncodingParameters.js.map +1 -1
  157. package/lib/commonjs/RTCRtpHeaderExtension.js.map +1 -1
  158. package/lib/commonjs/RTCRtpParameters.js.map +1 -1
  159. package/lib/commonjs/RTCRtpReceiveParameters.js.map +1 -1
  160. package/lib/commonjs/RTCRtpReceiver.js +7 -7
  161. package/lib/commonjs/RTCRtpReceiver.js.map +1 -1
  162. package/lib/commonjs/RTCRtpSendParameters.js +3 -3
  163. package/lib/commonjs/RTCRtpSendParameters.js.map +1 -1
  164. package/lib/commonjs/RTCRtpSender.js +7 -7
  165. package/lib/commonjs/RTCRtpSender.js.map +1 -1
  166. package/lib/commonjs/RTCRtpTransceiver.js.map +1 -1
  167. package/lib/commonjs/RTCSessionDescription.js.map +1 -1
  168. package/lib/commonjs/RTCTrackEvent.js +6 -6
  169. package/lib/commonjs/RTCTrackEvent.js.map +1 -1
  170. package/lib/commonjs/RTCUtil.js +28 -28
  171. package/lib/commonjs/RTCUtil.js.map +1 -1
  172. package/lib/commonjs/RTCView.js +5 -5
  173. package/lib/commonjs/RTCView.js.map +1 -1
  174. package/lib/commonjs/RTCView.web.js.map +1 -1
  175. package/lib/commonjs/ScreenCapturePickerView.js.map +1 -1
  176. package/lib/commonjs/ScreenCapturePickerView.web.js.map +1 -1
  177. package/lib/commonjs/getDisplayMedia.js.map +1 -1
  178. package/lib/commonjs/getUserMedia.js.map +1 -1
  179. package/lib/commonjs/index.js.map +1 -1
  180. package/lib/commonjs/index.web.js.map +1 -1
  181. package/lib/commonjs/webStream.js.map +1 -1
  182. package/lib/module/Constraints.js.map +1 -1
  183. package/lib/module/EventEmitter.js.map +1 -1
  184. package/lib/module/Logger.js.map +1 -1
  185. package/lib/module/MediaDevices.js +17 -17
  186. package/lib/module/MediaDevices.js.map +1 -1
  187. package/lib/module/MediaStream.js +19 -19
  188. package/lib/module/MediaStream.js.map +1 -1
  189. package/lib/module/MediaStreamError.js.map +1 -1
  190. package/lib/module/MediaStreamErrorEvent.js.map +1 -1
  191. package/lib/module/MediaStreamTrack.js +28 -28
  192. package/lib/module/MediaStreamTrack.js.map +1 -1
  193. package/lib/module/MediaStreamTrackEvent.js +6 -6
  194. package/lib/module/MediaStreamTrackEvent.js.map +1 -1
  195. package/lib/module/MessageEvent.js +7 -7
  196. package/lib/module/MessageEvent.js.map +1 -1
  197. package/lib/module/Permissions.js +28 -28
  198. package/lib/module/Permissions.js.map +1 -1
  199. package/lib/module/RTCAudioSession.js +4 -4
  200. package/lib/module/RTCAudioSession.js.map +1 -1
  201. package/lib/module/RTCDataChannel.js +2 -2
  202. package/lib/module/RTCDataChannel.js.map +1 -1
  203. package/lib/module/RTCDataChannelEvent.js +6 -6
  204. package/lib/module/RTCDataChannelEvent.js.map +1 -1
  205. package/lib/module/RTCDataPacketCryptor.js.map +1 -1
  206. package/lib/module/RTCDataPacketCryptorFactory.js.map +1 -1
  207. package/lib/module/RTCErrorEvent.js +3 -3
  208. package/lib/module/RTCErrorEvent.js.map +1 -1
  209. package/lib/module/RTCFrameCryptor.js +8 -8
  210. package/lib/module/RTCFrameCryptor.js.map +1 -1
  211. package/lib/module/RTCFrameCryptorFactory.js.map +1 -1
  212. package/lib/module/RTCIceCandidate.js.map +1 -1
  213. package/lib/module/RTCIceCandidateEvent.js +7 -7
  214. package/lib/module/RTCIceCandidateEvent.js.map +1 -1
  215. package/lib/module/RTCKeyProvider.js.map +1 -1
  216. package/lib/module/RTCPIPView.js +2 -2
  217. package/lib/module/RTCPIPView.js.map +1 -1
  218. package/lib/module/RTCPIPView.web.js.map +1 -1
  219. package/lib/module/RTCPeerConnection.js +36 -36
  220. package/lib/module/RTCPeerConnection.js.map +1 -1
  221. package/lib/module/RTCRtcpParameters.js.map +1 -1
  222. package/lib/module/RTCRtpCapabilities.js +2 -2
  223. package/lib/module/RTCRtpCapabilities.js.map +1 -1
  224. package/lib/module/RTCRtpCodecCapability.js.map +1 -1
  225. package/lib/module/RTCRtpCodecParameters.js.map +1 -1
  226. package/lib/module/RTCRtpEncodingParameters.js.map +1 -1
  227. package/lib/module/RTCRtpHeaderExtension.js.map +1 -1
  228. package/lib/module/RTCRtpParameters.js.map +1 -1
  229. package/lib/module/RTCRtpReceiveParameters.js.map +1 -1
  230. package/lib/module/RTCRtpReceiver.js +7 -7
  231. package/lib/module/RTCRtpReceiver.js.map +1 -1
  232. package/lib/module/RTCRtpSendParameters.js +3 -3
  233. package/lib/module/RTCRtpSendParameters.js.map +1 -1
  234. package/lib/module/RTCRtpSender.js +7 -7
  235. package/lib/module/RTCRtpSender.js.map +1 -1
  236. package/lib/module/RTCRtpTransceiver.js.map +1 -1
  237. package/lib/module/RTCSessionDescription.js.map +1 -1
  238. package/lib/module/RTCTrackEvent.js +6 -6
  239. package/lib/module/RTCTrackEvent.js.map +1 -1
  240. package/lib/module/RTCUtil.js +28 -28
  241. package/lib/module/RTCUtil.js.map +1 -1
  242. package/lib/module/RTCView.js +5 -5
  243. package/lib/module/RTCView.js.map +1 -1
  244. package/lib/module/RTCView.web.js.map +1 -1
  245. package/lib/module/ScreenCapturePickerView.js.map +1 -1
  246. package/lib/module/ScreenCapturePickerView.web.js.map +1 -1
  247. package/lib/module/getDisplayMedia.js.map +1 -1
  248. package/lib/module/getUserMedia.js.map +1 -1
  249. package/lib/module/index.js.map +1 -1
  250. package/lib/module/index.web.js.map +1 -1
  251. package/lib/module/webStream.js.map +1 -1
  252. package/lib/typescript/Constraints.d.ts +19 -19
  253. package/lib/typescript/EventEmitter.d.ts +6 -6
  254. package/lib/typescript/Logger.d.ts +13 -13
  255. package/lib/typescript/MediaDevices.d.ts +30 -30
  256. package/lib/typescript/MediaStream.d.ts +48 -48
  257. package/lib/typescript/MediaStreamError.d.ts +6 -6
  258. package/lib/typescript/MediaStreamErrorEvent.d.ts +6 -6
  259. package/lib/typescript/MediaStreamTrack.d.ts +101 -101
  260. package/lib/typescript/MediaStreamTrackEvent.d.ts +19 -19
  261. package/lib/typescript/MessageEvent.d.ts +20 -20
  262. package/lib/typescript/Permissions.d.ts +55 -55
  263. package/lib/typescript/RTCAudioSession.d.ts +10 -10
  264. package/lib/typescript/RTCDataChannel.d.ts +43 -43
  265. package/lib/typescript/RTCDataChannelEvent.d.ts +19 -19
  266. package/lib/typescript/RTCDataPacketCryptor.d.ts +12 -12
  267. package/lib/typescript/RTCDataPacketCryptorFactory.d.ts +6 -6
  268. package/lib/typescript/RTCErrorEvent.d.ts +12 -12
  269. package/lib/typescript/RTCFrameCryptor.d.ts +47 -47
  270. package/lib/typescript/RTCFrameCryptorFactory.d.ts +21 -21
  271. package/lib/typescript/RTCIceCandidate.d.ts +17 -17
  272. package/lib/typescript/RTCIceCandidateEvent.d.ts +20 -20
  273. package/lib/typescript/RTCKeyProvider.d.ts +21 -21
  274. package/lib/typescript/RTCPIPView.d.ts +15 -15
  275. package/lib/typescript/RTCPIPView.web.d.ts +13 -13
  276. package/lib/typescript/RTCPeerConnection.d.ts +117 -117
  277. package/lib/typescript/RTCRtcpParameters.d.ts +10 -10
  278. package/lib/typescript/RTCRtpCapabilities.d.ts +9 -9
  279. package/lib/typescript/RTCRtpCodecCapability.d.ts +7 -7
  280. package/lib/typescript/RTCRtpCodecParameters.d.ts +16 -16
  281. package/lib/typescript/RTCRtpEncodingParameters.d.ts +23 -23
  282. package/lib/typescript/RTCRtpHeaderExtension.d.ts +12 -12
  283. package/lib/typescript/RTCRtpParameters.d.ts +19 -19
  284. package/lib/typescript/RTCRtpReceiveParameters.d.ts +4 -4
  285. package/lib/typescript/RTCRtpReceiver.d.ts +21 -21
  286. package/lib/typescript/RTCRtpSendParameters.d.ts +20 -20
  287. package/lib/typescript/RTCRtpSender.d.ts +22 -22
  288. package/lib/typescript/RTCRtpTransceiver.d.ts +31 -31
  289. package/lib/typescript/RTCSessionDescription.d.ts +12 -12
  290. package/lib/typescript/RTCTrackEvent.d.ts +29 -29
  291. package/lib/typescript/RTCUtil.d.ts +37 -37
  292. package/lib/typescript/RTCView.d.ts +117 -117
  293. package/lib/typescript/RTCView.web.d.ts +25 -25
  294. package/lib/typescript/ScreenCapturePickerView.d.ts +2 -2
  295. package/lib/typescript/ScreenCapturePickerView.web.d.ts +1 -1
  296. package/lib/typescript/getDisplayMedia.d.ts +2 -2
  297. package/lib/typescript/getUserMedia.d.ts +7 -7
  298. package/lib/typescript/index.d.ts +22 -22
  299. package/lib/typescript/index.web.d.ts +101 -101
  300. package/lib/typescript/webStream.d.ts +3 -3
  301. package/livekit-react-native-webrtc.podspec +29 -29
  302. package/macos/RCTWebRTC.xcodeproj/project.pbxproj +324 -324
  303. package/macos/RCTWebRTC.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -7
  304. package/macos/RCTWebRTC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -8
  305. package/metro.config.js +7 -7
  306. package/metro.config.macos.js +14 -14
  307. package/package.json +66 -66
  308. package/react-native.config.js +11 -11
  309. package/src/.eslintrc.cjs +67 -67
  310. package/src/Constraints.ts +20 -20
  311. package/src/EventEmitter.ts +65 -65
  312. package/src/Logger.ts +49 -49
  313. package/src/MediaDevices.ts +53 -53
  314. package/src/MediaStream.ts +161 -161
  315. package/src/MediaStreamError.ts +12 -12
  316. package/src/MediaStreamErrorEvent.ts +11 -11
  317. package/src/MediaStreamTrack.ts +282 -282
  318. package/src/MediaStreamTrackEvent.ts +25 -25
  319. package/src/MessageEvent.ts +26 -26
  320. package/src/Permissions.ts +133 -133
  321. package/src/RTCAudioSession.ts +25 -25
  322. package/src/RTCDataChannel.ts +190 -190
  323. package/src/RTCDataChannelEvent.ts +28 -28
  324. package/src/RTCDataPacketCryptor.ts +90 -90
  325. package/src/RTCDataPacketCryptorFactory.ts +24 -24
  326. package/src/RTCErrorEvent.ts +20 -20
  327. package/src/RTCFrameCryptor.ts +162 -162
  328. package/src/RTCFrameCryptorFactory.ts +101 -101
  329. package/src/RTCIceCandidate.ts +29 -29
  330. package/src/RTCIceCandidateEvent.ts +26 -26
  331. package/src/RTCKeyProvider.ts +117 -117
  332. package/src/RTCPIPView.tsx +46 -46
  333. package/src/RTCPIPView.web.tsx +18 -18
  334. package/src/RTCPeerConnection.ts +935 -935
  335. package/src/RTCRtcpParameters.ts +23 -23
  336. package/src/RTCRtpCapabilities.ts +16 -16
  337. package/src/RTCRtpCodecCapability.ts +12 -12
  338. package/src/RTCRtpCodecParameters.ts +44 -44
  339. package/src/RTCRtpEncodingParameters.ts +90 -90
  340. package/src/RTCRtpHeaderExtension.ts +27 -27
  341. package/src/RTCRtpParameters.ts +37 -37
  342. package/src/RTCRtpReceiveParameters.ts +7 -7
  343. package/src/RTCRtpReceiver.ts +60 -60
  344. package/src/RTCRtpSendParameters.ts +63 -63
  345. package/src/RTCRtpSender.ts +78 -78
  346. package/src/RTCRtpTransceiver.ts +107 -107
  347. package/src/RTCSessionDescription.ts +30 -30
  348. package/src/RTCTrackEvent.ts +42 -42
  349. package/src/RTCUtil.ts +211 -211
  350. package/src/RTCView.ts +122 -122
  351. package/src/RTCView.web.tsx +80 -80
  352. package/src/ScreenCapturePickerView.ts +4 -4
  353. package/src/ScreenCapturePickerView.web.tsx +3 -3
  354. package/src/getDisplayMedia.ts +30 -30
  355. package/src/getUserMedia.ts +136 -136
  356. package/src/index.ts +107 -107
  357. package/src/index.web.ts +191 -191
  358. package/src/webStream.ts +31 -31
  359. package/tools/format.sh +6 -6
  360. package/tools/release.sh +45 -45
  361. package/tsconfig.json +17 -17
@@ -1,1643 +1,1649 @@
1
- package com.oney.WebRTCModule;
2
-
3
- import android.util.Log;
4
- import android.util.Pair;
5
- import android.util.SparseArray;
6
-
7
- import androidx.annotation.NonNull;
8
- import androidx.annotation.Nullable;
9
-
10
- import com.facebook.react.bridge.Arguments;
11
- import com.facebook.react.bridge.Callback;
12
- import com.facebook.react.bridge.Promise;
13
- import com.facebook.react.bridge.ReactApplicationContext;
14
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
15
- import com.facebook.react.bridge.ReactMethod;
16
- import com.facebook.react.bridge.ReadableArray;
17
- import com.facebook.react.bridge.ReadableMap;
18
- import com.facebook.react.bridge.ReadableMapKeySetIterator;
19
- import com.facebook.react.bridge.ReadableType;
20
- import com.facebook.react.bridge.WritableArray;
21
- import com.facebook.react.bridge.WritableMap;
22
- import com.facebook.react.module.annotations.ReactModule;
23
- import com.facebook.react.modules.core.DeviceEventManagerModule;
24
- import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoDecoderFactory;
25
- import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory;
26
- import com.oney.WebRTCModule.palabra.PalabraClient;
27
- import com.oney.WebRTCModule.palabra.PalabraConfig;
28
- import com.oney.WebRTCModule.palabra.PalabraListener;
29
-
30
- import org.webrtc.AddIceObserver;
31
- import org.webrtc.AudioProcessingFactory;
32
- import org.webrtc.AudioTrack;
33
- import org.webrtc.CryptoOptions;
34
- import org.webrtc.EglBase;
35
- import org.webrtc.IceCandidate;
36
- import org.webrtc.Loggable;
37
- import org.webrtc.Logging;
38
- import org.webrtc.MediaConstraints;
39
- import org.webrtc.MediaStream;
40
- import org.webrtc.MediaStreamTrack;
41
- import org.webrtc.PeerConnection;
42
- import org.webrtc.PeerConnectionFactory;
43
- import org.webrtc.RTCStatsReport;
44
- import org.webrtc.RtpCapabilities;
45
- import org.webrtc.RtpParameters;
46
- import org.webrtc.RtpSender;
47
- import org.webrtc.RtpTransceiver;
48
- import org.webrtc.SdpObserver;
49
- import org.webrtc.SessionDescription;
50
- import org.webrtc.SoftwareVideoDecoderFactory;
51
- import org.webrtc.SoftwareVideoEncoderFactory;
52
- import org.webrtc.VideoDecoderFactory;
53
- import org.webrtc.VideoEncoderFactory;
54
- import org.webrtc.VideoTrack;
55
- import org.webrtc.audio.AudioDeviceModule;
56
- import org.webrtc.audio.JavaAudioDeviceModule;
57
-
58
- import java.util.ArrayList;
59
- import java.util.HashMap;
60
- import java.util.List;
61
- import java.util.Map;
62
- import java.util.Objects;
63
- import java.util.concurrent.Callable;
64
- import java.util.concurrent.ExecutionException;
65
-
66
- @ReactModule(name = "WebRTCModule")
67
- public class WebRTCModule extends ReactContextBaseJavaModule {
68
- static final String TAG = WebRTCModule.class.getCanonicalName();
69
-
70
- PeerConnectionFactory mFactory;
71
- VideoEncoderFactory mVideoEncoderFactory;
72
- VideoDecoderFactory mVideoDecoderFactory;
73
- AudioDeviceModule mAudioDeviceModule;
74
-
75
- // Need to expose the peer connection codec factories here to get capabilities
76
- private final SparseArray<PeerConnectionObserver> mPeerConnectionObservers;
77
- final Map<String, MediaStream> localStreams;
78
-
79
- private final GetUserMediaImpl getUserMediaImpl;
80
-
81
- private PalabraClient palabraClient;
82
-
83
- public WebRTCModule(ReactApplicationContext reactContext) {
84
- super(reactContext);
85
-
86
- mPeerConnectionObservers = new SparseArray<>();
87
- localStreams = new HashMap<>();
88
-
89
- WebRTCModuleOptions options = WebRTCModuleOptions.getInstance();
90
-
91
- AudioDeviceModule adm = options.audioDeviceModule;
92
- VideoEncoderFactory encoderFactory = options.videoEncoderFactory;
93
- VideoDecoderFactory decoderFactory = options.videoDecoderFactory;
94
- Loggable injectableLogger = options.injectableLogger;
95
- Logging.Severity loggingSeverity = options.loggingSeverity;
96
- String fieldTrials = options.fieldTrials;
97
-
98
- PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(reactContext)
99
- .setFieldTrials(fieldTrials)
100
- .setNativeLibraryLoader(new LibraryLoader())
101
- .setInjectableLogger(injectableLogger, loggingSeverity)
102
- .createInitializationOptions());
103
-
104
- if (injectableLogger == null && loggingSeverity != null) {
105
- Logging.enableLogToDebugOutput(loggingSeverity);
106
- }
107
-
108
- if (encoderFactory == null || decoderFactory == null) {
109
- // Initialize EGL context required for HW acceleration.
110
- EglBase.Context eglContext = EglUtils.getRootEglBaseContext();
111
-
112
- if (eglContext != null) {
113
- encoderFactory = new H264AndSoftwareVideoEncoderFactory(eglContext);
114
- decoderFactory = new H264AndSoftwareVideoDecoderFactory(eglContext);
115
- } else {
116
- encoderFactory = new SoftwareVideoEncoderFactory();
117
- decoderFactory = new SoftwareVideoDecoderFactory();
118
- }
119
- }
120
-
121
- if (adm == null) {
122
- adm = JavaAudioDeviceModule.builder(reactContext).createAudioDeviceModule();
123
- }
124
-
125
- AudioProcessingFactory audioProcessingFactory = null;
126
- try {
127
- if (options.audioProcessingFactoryFactory != null) {
128
- audioProcessingFactory = options.audioProcessingFactoryFactory.call();
129
- }
130
- } catch (Exception e) {
131
- // do nothing.
132
- }
133
-
134
- Log.d(TAG, "Using video encoder factory: " + encoderFactory.getClass().getCanonicalName());
135
- Log.d(TAG, "Using video decoder factory: " + decoderFactory.getClass().getCanonicalName());
136
-
137
- PeerConnectionFactory.Builder pcFactoryBuilder = PeerConnectionFactory.builder()
138
- .setAudioDeviceModule(adm)
139
- .setVideoEncoderFactory(encoderFactory)
140
- .setVideoDecoderFactory(decoderFactory);
141
-
142
- if (audioProcessingFactory != null) {
143
- pcFactoryBuilder.setAudioProcessingFactory(audioProcessingFactory);
144
- }
145
-
146
- mFactory = pcFactoryBuilder.createPeerConnectionFactory();
147
-
148
- // PeerConnectionFactory now owns the adm native pointer, and we don't need it anymore.
149
- adm.release();
150
-
151
- // Saving the encoder and decoder factories to get codec info later when needed.
152
- mVideoEncoderFactory = encoderFactory;
153
- mVideoDecoderFactory = decoderFactory;
154
- mAudioDeviceModule = adm;
155
-
156
- getUserMediaImpl = new GetUserMediaImpl(this, reactContext);
157
- }
158
-
159
- @NonNull
160
- @Override
161
- public String getName() {
162
- return "WebRTCModule";
163
- }
164
-
165
- public PeerConnectionObserver getPeerConnectionObserver(int id) {
166
- return mPeerConnectionObservers.get(id);
167
- }
168
- private PeerConnection getPeerConnection(int id) {
169
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
170
- return (pco == null) ? null : pco.getPeerConnection();
171
- }
172
-
173
- void sendEvent(String eventName, @Nullable ReadableMap params) {
174
- getReactApplicationContext()
175
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
176
- .emit(eventName, params);
177
- }
178
-
179
- private PeerConnection.IceServer createIceServer(String url) {
180
- return PeerConnection.IceServer.builder(url).createIceServer();
181
- }
182
-
183
- private PeerConnection.IceServer createIceServer(String url, String username, String credential) {
184
- return PeerConnection.IceServer.builder(url).setUsername(username).setPassword(credential).createIceServer();
185
- }
186
-
187
- private List<PeerConnection.IceServer> createIceServers(ReadableArray iceServersArray) {
188
- final int size = (iceServersArray == null) ? 0 : iceServersArray.size();
189
- List<PeerConnection.IceServer> iceServers = new ArrayList<>(size);
190
- for (int i = 0; i < size; i++) {
191
- ReadableMap iceServerMap = iceServersArray.getMap(i);
192
- boolean hasUsernameAndCredential = iceServerMap.hasKey("username") && iceServerMap.hasKey("credential");
193
- if (iceServerMap.hasKey("urls")) {
194
- switch (iceServerMap.getType("urls")) {
195
- case String:
196
- if (hasUsernameAndCredential) {
197
- iceServers.add(createIceServer(iceServerMap.getString("urls"),
198
- iceServerMap.getString("username"),
199
- iceServerMap.getString("credential")));
200
- } else {
201
- iceServers.add(createIceServer(iceServerMap.getString("urls")));
202
- }
203
- break;
204
- case Array:
205
- ReadableArray urls = iceServerMap.getArray("urls");
206
- for (int j = 0; j < urls.size(); j++) {
207
- String url = urls.getString(j);
208
- if (hasUsernameAndCredential) {
209
- iceServers.add(createIceServer(
210
- url, iceServerMap.getString("username"), iceServerMap.getString("credential")));
211
- } else {
212
- iceServers.add(createIceServer(url));
213
- }
214
- }
215
- break;
216
- }
217
- }
218
- }
219
- return iceServers;
220
- }
221
-
222
- private PeerConnection.RTCConfiguration parseRTCConfiguration(ReadableMap map) {
223
- ReadableArray iceServersArray = null;
224
- if (map != null && map.hasKey("iceServers")) {
225
- iceServersArray = map.getArray("iceServers");
226
- }
227
- List<PeerConnection.IceServer> iceServers = createIceServers(iceServersArray);
228
-
229
- PeerConnection.RTCConfiguration conf = new PeerConnection.RTCConfiguration(iceServers);
230
- conf.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
231
-
232
- // Required for perfect negotiation.
233
- conf.enableImplicitRollback = true;
234
-
235
- // Enable GCM ciphers.
236
- CryptoOptions cryptoOptions = CryptoOptions.builder()
237
- .setEnableGcmCryptoSuites(true)
238
- .setEnableAes128Sha1_32CryptoCipher(false)
239
- .setEnableEncryptedRtpHeaderExtensions(false)
240
- .setRequireFrameEncryption(false)
241
- .createCryptoOptions();
242
- conf.cryptoOptions = cryptoOptions;
243
-
244
- if (map == null) {
245
- return conf;
246
- }
247
-
248
- // iceTransportPolicy (public api)
249
- if (map.hasKey("iceTransportPolicy") && map.getType("iceTransportPolicy") == ReadableType.String) {
250
- final String v = map.getString("iceTransportPolicy");
251
- if (v != null) {
252
- switch (v) {
253
- case "all": // public
254
- conf.iceTransportsType = PeerConnection.IceTransportsType.ALL;
255
- break;
256
- case "relay": // public
257
- conf.iceTransportsType = PeerConnection.IceTransportsType.RELAY;
258
- break;
259
- case "nohost":
260
- conf.iceTransportsType = PeerConnection.IceTransportsType.NOHOST;
261
- break;
262
- case "none":
263
- conf.iceTransportsType = PeerConnection.IceTransportsType.NONE;
264
- break;
265
- }
266
- }
267
- }
268
-
269
- // bundlePolicy (public api)
270
- if (map.hasKey("bundlePolicy") && map.getType("bundlePolicy") == ReadableType.String) {
271
- final String v = map.getString("bundlePolicy");
272
- if (v != null) {
273
- switch (v) {
274
- case "balanced": // public
275
- conf.bundlePolicy = PeerConnection.BundlePolicy.BALANCED;
276
- break;
277
- case "max-compat": // public
278
- conf.bundlePolicy = PeerConnection.BundlePolicy.MAXCOMPAT;
279
- break;
280
- case "max-bundle": // public
281
- conf.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE;
282
- break;
283
- }
284
- }
285
- }
286
-
287
- // rtcpMuxPolicy (public api)
288
- if (map.hasKey("rtcpMuxPolicy") && map.getType("rtcpMuxPolicy") == ReadableType.String) {
289
- final String v = map.getString("rtcpMuxPolicy");
290
- if (v != null) {
291
- switch (v) {
292
- case "negotiate": // public
293
- conf.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.NEGOTIATE;
294
- break;
295
- case "require": // public
296
- conf.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE;
297
- break;
298
- }
299
- }
300
- }
301
-
302
- // FIXME: peerIdentity of type DOMString (public api)
303
- // FIXME: certificates of type sequence<RTCCertificate> (public api)
304
-
305
- // iceCandidatePoolSize of type unsigned short, defaulting to 0
306
- if (map.hasKey("iceCandidatePoolSize") && map.getType("iceCandidatePoolSize") == ReadableType.Number) {
307
- final int v = map.getInt("iceCandidatePoolSize");
308
- if (v > 0) {
309
- conf.iceCandidatePoolSize = v;
310
- }
311
- }
312
-
313
- // === below is private api in webrtc ===
314
-
315
- // tcpCandidatePolicy (private api)
316
- if (map.hasKey("tcpCandidatePolicy") && map.getType("tcpCandidatePolicy") == ReadableType.String) {
317
- final String v = map.getString("tcpCandidatePolicy");
318
- if (v != null) {
319
- switch (v) {
320
- case "enabled":
321
- conf.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.ENABLED;
322
- break;
323
- case "disabled":
324
- conf.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
325
- break;
326
- }
327
- }
328
- }
329
-
330
- // candidateNetworkPolicy (private api)
331
- if (map.hasKey("candidateNetworkPolicy") && map.getType("candidateNetworkPolicy") == ReadableType.String) {
332
- final String v = map.getString("candidateNetworkPolicy");
333
- if (v != null) {
334
- switch (v) {
335
- case "all":
336
- conf.candidateNetworkPolicy = PeerConnection.CandidateNetworkPolicy.ALL;
337
- break;
338
- case "low_cost":
339
- conf.candidateNetworkPolicy = PeerConnection.CandidateNetworkPolicy.LOW_COST;
340
- break;
341
- }
342
- }
343
- }
344
-
345
- // KeyType (private api)
346
- if (map.hasKey("keyType") && map.getType("keyType") == ReadableType.String) {
347
- final String v = map.getString("keyType");
348
- if (v != null) {
349
- switch (v) {
350
- case "RSA":
351
- conf.keyType = PeerConnection.KeyType.RSA;
352
- break;
353
- case "ECDSA":
354
- conf.keyType = PeerConnection.KeyType.ECDSA;
355
- break;
356
- }
357
- }
358
- }
359
-
360
- // continualGatheringPolicy (private api)
361
- if (map.hasKey("continualGatheringPolicy") && map.getType("continualGatheringPolicy") == ReadableType.String) {
362
- final String v = map.getString("continualGatheringPolicy");
363
- if (v != null) {
364
- switch (v) {
365
- case "gather_once":
366
- conf.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_ONCE;
367
- break;
368
- case "gather_continually":
369
- conf.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY;
370
- break;
371
- }
372
- }
373
- }
374
-
375
- // audioJitterBufferMaxPackets (private api)
376
- if (map.hasKey("audioJitterBufferMaxPackets")
377
- && map.getType("audioJitterBufferMaxPackets") == ReadableType.Number) {
378
- final int v = map.getInt("audioJitterBufferMaxPackets");
379
- if (v > 0) {
380
- conf.audioJitterBufferMaxPackets = v;
381
- }
382
- }
383
-
384
- // iceConnectionReceivingTimeout (private api)
385
- if (map.hasKey("iceConnectionReceivingTimeout")
386
- && map.getType("iceConnectionReceivingTimeout") == ReadableType.Number) {
387
- final int v = map.getInt("iceConnectionReceivingTimeout");
388
- conf.iceConnectionReceivingTimeout = v;
389
- }
390
-
391
- // iceBackupCandidatePairPingInterval (private api)
392
- if (map.hasKey("iceBackupCandidatePairPingInterval")
393
- && map.getType("iceBackupCandidatePairPingInterval") == ReadableType.Number) {
394
- final int v = map.getInt("iceBackupCandidatePairPingInterval");
395
- conf.iceBackupCandidatePairPingInterval = v;
396
- }
397
-
398
- // audioJitterBufferFastAccelerate (private api)
399
- if (map.hasKey("audioJitterBufferFastAccelerate")
400
- && map.getType("audioJitterBufferFastAccelerate") == ReadableType.Boolean) {
401
- final boolean v = map.getBoolean("audioJitterBufferFastAccelerate");
402
- conf.audioJitterBufferFastAccelerate = v;
403
- }
404
-
405
- // pruneTurnPorts (private api)
406
- if (map.hasKey("pruneTurnPorts") && map.getType("pruneTurnPorts") == ReadableType.Boolean) {
407
- final boolean v = map.getBoolean("pruneTurnPorts");
408
- conf.pruneTurnPorts = v;
409
- }
410
-
411
- // presumeWritableWhenFullyRelayed (private api)
412
- if (map.hasKey("presumeWritableWhenFullyRelayed")
413
- && map.getType("presumeWritableWhenFullyRelayed") == ReadableType.Boolean) {
414
- final boolean v = map.getBoolean("presumeWritableWhenFullyRelayed");
415
- conf.presumeWritableWhenFullyRelayed = v;
416
- }
417
-
418
- return conf;
419
- }
420
-
421
- @ReactMethod(isBlockingSynchronousMethod = true)
422
- public boolean peerConnectionInit(ReadableMap configuration, int id) {
423
- PeerConnection.RTCConfiguration rtcConfiguration = parseRTCConfiguration(configuration);
424
-
425
- try {
426
- return (boolean) ThreadUtils
427
- .submitToExecutor(() -> {
428
- PeerConnectionObserver observer = new PeerConnectionObserver(this, id);
429
- PeerConnection peerConnection = mFactory.createPeerConnection(rtcConfiguration, observer);
430
- if (peerConnection == null) {
431
- return false;
432
- }
433
- observer.setPeerConnection(peerConnection);
434
- mPeerConnectionObservers.put(id, observer);
435
- return true;
436
- })
437
- .get();
438
- } catch (ExecutionException | InterruptedException e) {
439
- e.printStackTrace();
440
- throw new RuntimeException(e);
441
- }
442
- }
443
-
444
- MediaStream getStreamForReactTag(String streamReactTag) {
445
- // This function _only_ gets called from WebRTCView, in the UI thread.
446
- // Hence make sure we run this code in the executor or we run at the risk
447
- // of being out of sync.
448
- try {
449
- return (MediaStream) ThreadUtils
450
- .submitToExecutor((Callable<Object>) () -> {
451
- MediaStream stream = localStreams.get(streamReactTag);
452
-
453
- if (stream != null) {
454
- return stream;
455
- }
456
-
457
- for (int i = 0, size = mPeerConnectionObservers.size(); i < size; i++) {
458
- PeerConnectionObserver pco = mPeerConnectionObservers.valueAt(i);
459
- stream = pco.remoteStreams.get(streamReactTag);
460
- if (stream != null) {
461
- return stream;
462
- }
463
- }
464
-
465
- return null;
466
- })
467
- .get();
468
- } catch (ExecutionException | InterruptedException e) {
469
- return null;
470
- }
471
- }
472
-
473
- public MediaStreamTrack getTrack(int pcId, String trackId) {
474
- if (pcId == -1) {
475
- return getLocalTrack(trackId);
476
- }
477
-
478
- PeerConnectionObserver pco = mPeerConnectionObservers.get(pcId);
479
- if (pco == null) {
480
- Log.d(TAG, "getTrack(): could not find PeerConnection");
481
- return null;
482
- }
483
-
484
- return pco.remoteTracks.get(trackId);
485
- }
486
-
487
- MediaStreamTrack getLocalTrack(String trackId) {
488
- return getUserMediaImpl.getTrack(trackId);
489
- }
490
-
491
- public VideoTrack createVideoTrack(AbstractVideoCaptureController videoCaptureController) {
492
- return getUserMediaImpl.createVideoTrack(videoCaptureController);
493
- }
494
-
495
- public void createStream(
496
- MediaStreamTrack[] tracks, GetUserMediaImpl.BiConsumer<String, ArrayList<WritableMap>> successCallback) {
497
- getUserMediaImpl.createStream(tracks, successCallback);
498
- }
499
-
500
- /**
501
- * Turns an "options" <tt>ReadableMap</tt> into a <tt>MediaConstraints</tt> object.
502
- *
503
- * @param options A <tt>ReadableMap</tt> which represents a JavaScript
504
- * object specifying the options to be parsed into a
505
- * <tt>MediaConstraints</tt> instance.
506
- * @return A new <tt>MediaConstraints</tt> instance initialized with the
507
- * mandatory keys and values specified by <tt>options</tt>.
508
- */
509
- MediaConstraints constraintsForOptions(ReadableMap options) {
510
- MediaConstraints mediaConstraints = new MediaConstraints();
511
- ReadableMapKeySetIterator keyIterator = options.keySetIterator();
512
-
513
- while (keyIterator.hasNextKey()) {
514
- String key = keyIterator.nextKey();
515
- String value = ReactBridgeUtil.getMapStrValue(options, key);
516
-
517
- mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(key, value));
518
- }
519
-
520
- return mediaConstraints;
521
- }
522
-
523
- @ReactMethod(isBlockingSynchronousMethod = true)
524
- public WritableMap peerConnectionAddTransceiver(int id, ReadableMap options) {
525
- try {
526
- return (WritableMap) ThreadUtils
527
- .submitToExecutor((Callable<Object>) () -> {
528
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
529
- if (pco == null) {
530
- Log.d(TAG, "peerConnectionAddTransceiver() peerConnection is null");
531
- return null;
532
- }
533
-
534
- RtpTransceiver transceiver = null;
535
- if (options.hasKey("type")) {
536
- String kind = options.getString("type");
537
- transceiver = pco.addTransceiver(SerializeUtils.parseMediaType(kind),
538
- SerializeUtils.parseTransceiverOptions(options.getMap("init")));
539
- } else if (options.hasKey("trackId")) {
540
- String trackId = options.getString("trackId");
541
- MediaStreamTrack track = getLocalTrack(trackId);
542
- transceiver = pco.addTransceiver(
543
- track, SerializeUtils.parseTransceiverOptions(options.getMap("init")));
544
-
545
- } else {
546
- // This should technically never happen as the JS side checks for that.
547
- Log.d(TAG, "peerConnectionAddTransceiver() no type nor trackId provided in options");
548
- return null;
549
- }
550
-
551
- if (transceiver == null) {
552
- Log.d(TAG, "peerConnectionAddTransceiver() Error adding transceiver");
553
- return null;
554
- }
555
- WritableMap params = Arguments.createMap();
556
- // We need to get a unique order at which the transceiver was created
557
- // to reorder the cached array of transceivers on the JS layer.
558
- params.putInt("transceiverOrder", pco.getNextTransceiverId());
559
- params.putMap("transceiver", SerializeUtils.serializeTransceiver(id, transceiver));
560
- return params;
561
- })
562
- .get();
563
- } catch (InterruptedException | ExecutionException e) {
564
- Log.d(TAG, "peerConnectionAddTransceiver() " + e.getMessage());
565
- return null;
566
- }
567
- }
568
-
569
- @ReactMethod(isBlockingSynchronousMethod = true)
570
- public WritableMap peerConnectionAddTrack(int id, String trackId, ReadableMap options) {
571
- try {
572
- return (WritableMap) ThreadUtils
573
- .submitToExecutor((Callable<Object>) () -> {
574
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
575
- if (pco == null) {
576
- Log.d(TAG, "peerConnectionAddTrack() peerConnection is null");
577
- return null;
578
- }
579
-
580
- MediaStreamTrack track = getLocalTrack(trackId);
581
- if (track == null) {
582
- Log.w(TAG, "peerConnectionAddTrack() couldn't find track " + trackId);
583
- return null;
584
- }
585
-
586
- List<String> streamIds = new ArrayList<>();
587
- if (options.hasKey("streamIds")) {
588
- ReadableArray rawStreamIds = options.getArray("streamIds");
589
- if (rawStreamIds != null) {
590
- for (int i = 0; i < rawStreamIds.size(); i++) {
591
- streamIds.add(rawStreamIds.getString(i));
592
- }
593
- }
594
- }
595
- RtpSender sender = pco.getPeerConnection().addTrack(track, streamIds);
596
-
597
- // Need to get the corresponding transceiver as well
598
- RtpTransceiver transceiver = pco.getTransceiver(sender.id());
599
-
600
- // We need the transceiver creation order to reorder the transceivers array
601
- // in the JS layer.
602
- WritableMap params = Arguments.createMap();
603
- params.putInt("transceiverOrder", pco.getNextTransceiverId());
604
- params.putMap("transceiver", SerializeUtils.serializeTransceiver(id, transceiver));
605
- params.putMap("sender", SerializeUtils.serializeSender(id, sender));
606
- return params;
607
- })
608
- .get();
609
- } catch (InterruptedException | ExecutionException e) {
610
- Log.d(TAG, "peerConnectionAddTrack() " + e.getMessage());
611
- return null;
612
- }
613
- }
614
-
615
- @ReactMethod(isBlockingSynchronousMethod = true)
616
- public boolean peerConnectionRemoveTrack(int id, String senderId) {
617
- try {
618
- return (boolean) ThreadUtils
619
- .submitToExecutor((Callable<Object>) () -> {
620
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
621
- if (pco == null) {
622
- Log.d(TAG, "peerConnectionRemoveTrack() peerConnection is null");
623
- return false;
624
- }
625
- RtpSender sender = pco.getSender(senderId);
626
- if (sender == null) {
627
- Log.w(TAG, "peerConnectionRemoveTrack() sender is null");
628
- return false;
629
- }
630
-
631
- return pco.getPeerConnection().removeTrack(sender);
632
- })
633
- .get();
634
- } catch (InterruptedException | ExecutionException e) {
635
- Log.d(TAG, "peerConnectionRemoveTrack() " + e.getMessage());
636
- return false;
637
- }
638
- }
639
-
640
- @ReactMethod
641
- public void senderSetParameters(int id, String senderId, ReadableMap options, Promise promise) {
642
- ThreadUtils.runOnExecutor(() -> {
643
- try {
644
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
645
- if (pco == null) {
646
- Log.d(TAG, "senderSetParameters() peerConnectionObserver is null");
647
- promise.reject(new Exception("Peer Connection is not initialized"));
648
- return;
649
- }
650
-
651
- RtpSender sender = pco.getSender(senderId);
652
- if (sender == null) {
653
- Log.w(TAG, "senderSetParameters() sender is null");
654
- promise.reject(new Exception("Could not get sender"));
655
- return;
656
- }
657
-
658
- RtpParameters params = sender.getParameters();
659
- params = SerializeUtils.updateRtpParameters(options, params);
660
- sender.setParameters(params);
661
- promise.resolve(SerializeUtils.serializeRtpParameters(sender.getParameters()));
662
- } catch (Exception e) {
663
- Log.d(TAG, "senderSetParameters: " + e.getMessage());
664
- promise.reject(e);
665
- }
666
- });
667
- }
668
-
669
- @ReactMethod
670
- public void transceiverStop(int id, String senderId, Promise promise) {
671
- ThreadUtils.runOnExecutor(() -> {
672
- try {
673
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
674
- if (pco == null) {
675
- Log.d(TAG, "transceiverStop() peerConnectionObserver is null");
676
- promise.reject(new Exception("Peer Connection is not initialized"));
677
- return;
678
- }
679
- RtpTransceiver transceiver = pco.getTransceiver(senderId);
680
- if (transceiver == null) {
681
- Log.w(TAG, "transceiverStop() transceiver is null");
682
- promise.reject(new Exception("Could not get transceiver"));
683
- return;
684
- }
685
-
686
- transceiver.stopStandard();
687
- promise.resolve(true);
688
- } catch (Exception e) {
689
- Log.d(TAG, "transceiverStop(): " + e.getMessage());
690
- promise.reject(e);
691
- }
692
- });
693
- }
694
-
695
- @ReactMethod
696
- public void senderReplaceTrack(int id, String senderId, String trackId, Promise promise) {
697
- ThreadUtils.runOnExecutor(() -> {
698
- try {
699
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
700
- if (pco == null) {
701
- Log.d(TAG, "senderReplaceTrack() peerConnectionObserver is null");
702
- promise.reject(new Exception("Peer Connection is not initialized"));
703
- return;
704
- }
705
-
706
- RtpSender sender = pco.getSender(senderId);
707
- if (sender == null) {
708
- Log.w(TAG, "senderReplaceTrack() sender is null");
709
- promise.reject(new Exception("Could not get sender"));
710
- return;
711
- }
712
-
713
- MediaStreamTrack track = getLocalTrack(trackId);
714
- sender.setTrack(track, false);
715
- promise.resolve(true);
716
- } catch (Exception e) {
717
- Log.d(TAG, "senderReplaceTrack(): " + e.getMessage());
718
- promise.reject(e);
719
- }
720
- });
721
- }
722
-
723
- @ReactMethod
724
- public void transceiverSetDirection(int id, String senderId, String direction, Promise promise) {
725
- ThreadUtils.runOnExecutor(() -> {
726
- WritableMap identifier = Arguments.createMap();
727
- WritableMap params = Arguments.createMap();
728
- identifier.putInt("peerConnectionId", id);
729
- identifier.putString("transceiverId", senderId);
730
- try {
731
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
732
- if (pco == null) {
733
- Log.d(TAG, "transceiverSetDirection() peerConnectionObserver is null");
734
- promise.reject(new Exception("Peer Connection is not initialized"));
735
- return;
736
- }
737
- RtpTransceiver transceiver = pco.getTransceiver(senderId);
738
- if (transceiver == null) {
739
- Log.d(TAG, "transceiverSetDirection() transceiver is null");
740
- promise.reject(new Exception("Could not get sender"));
741
- return;
742
- }
743
-
744
- transceiver.setDirection(SerializeUtils.parseDirection(direction));
745
-
746
- promise.resolve(true);
747
- } catch (Exception e) {
748
- Log.d(TAG, "transceiverSetDirection(): " + e.getMessage());
749
- promise.reject(e);
750
- }
751
- });
752
- }
753
-
754
- @ReactMethod(isBlockingSynchronousMethod = true)
755
- public boolean transceiverSetCodecPreferences(int id, String senderId, ReadableArray codecPreferences) {
756
- ThreadUtils.runOnExecutor(() -> {
757
- WritableMap identifier = Arguments.createMap();
758
- WritableMap params = Arguments.createMap();
759
- identifier.putInt("peerConnectionId", id);
760
- identifier.putString("transceiverId", senderId);
761
- try {
762
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
763
- if (pco == null) {
764
- Log.d(TAG, "transceiverSetDirection() peerConnectionObserver is null");
765
- return;
766
- }
767
- RtpTransceiver transceiver = pco.getTransceiver(senderId);
768
- if (transceiver == null) {
769
- Log.d(TAG, "transceiverSetDirection() transceiver is null");
770
- return;
771
- }
772
-
773
- // Convert JSON codec capabilities to the actual objects.
774
- RtpTransceiver.RtpTransceiverDirection direction = transceiver.getDirection();
775
- List<Pair<Map<String, Object>, RtpCapabilities.CodecCapability>> availableCodecs = new ArrayList<>();
776
-
777
- if (direction.equals(RtpTransceiver.RtpTransceiverDirection.SEND_RECV)
778
- || direction.equals(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY)) {
779
- RtpCapabilities capabilities = mFactory.getRtpSenderCapabilities(transceiver.getMediaType());
780
- for (RtpCapabilities.CodecCapability codec : capabilities.codecs) {
781
- Map<String, Object> codecDict = SerializeUtils.serializeRtpCapabilitiesCodec(codec).toHashMap();
782
- availableCodecs.add(new Pair<>(codecDict, codec));
783
- }
784
- }
785
-
786
- if (direction.equals(RtpTransceiver.RtpTransceiverDirection.SEND_RECV)
787
- || direction.equals(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY)) {
788
- RtpCapabilities capabilities = mFactory.getRtpReceiverCapabilities(transceiver.getMediaType());
789
- for (RtpCapabilities.CodecCapability codec : capabilities.codecs) {
790
- Map<String, Object> codecDict = SerializeUtils.serializeRtpCapabilitiesCodec(codec).toHashMap();
791
- availableCodecs.add(new Pair<>(codecDict, codec));
792
- }
793
- }
794
-
795
- // Codec preferences is order sensitive.
796
- List<RtpCapabilities.CodecCapability> codecsToSet = new ArrayList<>();
797
-
798
- for (int i = 0; i < codecPreferences.size(); i++) {
799
- Map<String, Object> codecPref = codecPreferences.getMap(i).toHashMap();
800
- for (Pair<Map<String, Object>, RtpCapabilities.CodecCapability> pair : availableCodecs) {
801
- Map<String, Object> availableCodecDict = pair.first;
802
- if (codecPref.equals(availableCodecDict)) {
803
- codecsToSet.add(pair.second);
804
- break;
805
- }
806
- }
807
- }
808
-
809
- transceiver.setCodecPreferences(codecsToSet);
810
- } catch (Exception e) {
811
- Log.d(TAG, "transceiverSetCodecPreferences(): " + e.getMessage());
812
- }
813
- });
814
- return true;
815
- }
816
-
817
- @ReactMethod
818
- public void getDisplayMedia(Promise promise) {
819
- ThreadUtils.runOnExecutor(() -> getUserMediaImpl.getDisplayMedia(promise));
820
- }
821
-
822
- @ReactMethod
823
- public void getUserMedia(ReadableMap constraints, Callback successCallback, Callback errorCallback) {
824
- ThreadUtils.runOnExecutor(() -> getUserMediaImpl.getUserMedia(constraints, successCallback, errorCallback));
825
- }
826
-
827
- @ReactMethod
828
- public void enumerateDevices(Callback callback) {
829
- ThreadUtils.runOnExecutor(() -> callback.invoke(getUserMediaImpl.enumerateDevices()));
830
- }
831
-
832
- @ReactMethod
833
- public void mediaStreamCreate(String id) {
834
- ThreadUtils.runOnExecutor(() -> {
835
- MediaStream mediaStream = mFactory.createLocalMediaStream(id);
836
- localStreams.put(id, mediaStream);
837
- });
838
- }
839
-
840
- @ReactMethod
841
- public void mediaStreamAddTrack(String streamId, int pcId, String trackId) {
842
- ThreadUtils.runOnExecutor(() -> {
843
- MediaStream stream = localStreams.get(streamId);
844
- if (stream == null) {
845
- Log.d(TAG, "mediaStreamAddTrack() could not find stream " + streamId);
846
- return;
847
- }
848
-
849
- MediaStreamTrack track = getTrack(pcId, trackId);
850
- if (track == null) {
851
- Log.d(TAG, "mediaStreamAddTrack() could not find track " + trackId);
852
- return;
853
- }
854
-
855
- String kind = track.kind();
856
- if ("audio".equals(kind)) {
857
- stream.addTrack((AudioTrack) track);
858
- } else if ("video".equals(kind)) {
859
- stream.addTrack((VideoTrack) track);
860
- }
861
- });
862
- }
863
-
864
- @ReactMethod
865
- public void mediaStreamRemoveTrack(String streamId, int pcId, String trackId) {
866
- ThreadUtils.runOnExecutor(() -> {
867
- MediaStream stream = localStreams.get(streamId);
868
- if (stream == null) {
869
- Log.d(TAG, "mediaStreamRemoveTrack() could not find stream " + streamId);
870
- return;
871
- }
872
-
873
- MediaStreamTrack track = getTrack(pcId, trackId);
874
- if (track == null) {
875
- Log.d(TAG, "mediaStreamRemoveTrack() could not find track " + trackId);
876
- return;
877
- }
878
-
879
- String kind = track.kind();
880
- if ("audio".equals(kind)) {
881
- stream.removeTrack((AudioTrack) track);
882
- } else if ("video".equals(kind)) {
883
- stream.removeTrack((VideoTrack) track);
884
- }
885
- });
886
- }
887
-
888
- @ReactMethod
889
- public void mediaStreamRelease(String id) {
890
- ThreadUtils.runOnExecutor(() -> {
891
- MediaStream stream = localStreams.get(id);
892
- if (stream == null) {
893
- Log.d(TAG, "mediaStreamRelease() stream is null");
894
- return;
895
- }
896
- localStreams.remove(id);
897
- stream.dispose();
898
- });
899
- }
900
-
901
- @ReactMethod
902
- public void mediaStreamTrackRelease(String id) {
903
- ThreadUtils.runOnExecutor(() -> {
904
- MediaStreamTrack track = getLocalTrack(id);
905
- if (track == null) {
906
- Log.d(TAG, "mediaStreamTrackRelease() track is null");
907
- return;
908
- }
909
- track.setEnabled(false);
910
- getUserMediaImpl.disposeTrack(id);
911
- });
912
- }
913
-
914
- @ReactMethod
915
- public void mediaStreamTrackSetEnabled(int pcId, String id, boolean enabled) {
916
- ThreadUtils.runOnExecutor(() -> {
917
- MediaStreamTrack track = getTrack(pcId, id);
918
- if (track == null) {
919
- Log.d(TAG, "mediaStreamTrackSetEnabled() could not find track " + id);
920
- return;
921
- }
922
-
923
- if (track.enabled() == enabled) {
924
- return;
925
- }
926
- track.setEnabled(enabled);
927
- getUserMediaImpl.mediaStreamTrackSetEnabled(id, enabled);
928
- });
929
- }
930
-
931
- @ReactMethod
932
- public void mediaStreamTrackApplyConstraints(String id, ReadableMap constraints, Promise promise) {
933
- ThreadUtils.runOnExecutor(() -> {
934
- MediaStreamTrack track = getLocalTrack(id);
935
- if (track != null) {
936
- getUserMediaImpl.applyConstraints(id, constraints, promise);
937
- } else {
938
- promise.reject(new Exception("mediaStreamTrackApplyConstraints() could not find track " + id));
939
- }
940
- });
941
- }
942
-
943
- @ReactMethod
944
- public void mediaStreamTrackSetVolume(int pcId, String id, double volume) {
945
- ThreadUtils.runOnExecutor(() -> {
946
- MediaStreamTrack track = getTrack(pcId, id);
947
- if (track == null) {
948
- Log.d(TAG, "mediaStreamTrackSetVolume() could not find track " + id);
949
- return;
950
- }
951
-
952
- if (!(track instanceof AudioTrack)) {
953
- Log.d(TAG, "mediaStreamTrackSetVolume() track is not an AudioTrack!");
954
- return;
955
- }
956
-
957
- ((AudioTrack) track).setVolume(volume);
958
- });
959
- }
960
-
961
- /**
962
- * This serializes the transceivers current direction and mid and returns them
963
- * for update when an sdp negotiation/renegotiation happens
964
- */
965
- private ReadableArray getTransceiversInfo(PeerConnection peerConnection) {
966
- WritableArray transceiverUpdates = Arguments.createArray();
967
-
968
- for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
969
- WritableMap transceiverUpdate = Arguments.createMap();
970
-
971
- RtpTransceiver.RtpTransceiverDirection direction = transceiver.getCurrentDirection();
972
- if (direction != null) {
973
- String directionSerialized = SerializeUtils.serializeDirection(direction);
974
- transceiverUpdate.putString("currentDirection", directionSerialized);
975
- }
976
-
977
- transceiverUpdate.putString("transceiverId", transceiver.getSender().id());
978
- transceiverUpdate.putString("mid", transceiver.getMid());
979
- transceiverUpdate.putBoolean("isStopped", transceiver.isStopped());
980
- transceiverUpdate.putMap("senderRtpParameters",
981
- SerializeUtils.serializeRtpParameters(transceiver.getSender().getParameters()));
982
- transceiverUpdate.putMap("receiverRtpParameters",
983
- SerializeUtils.serializeRtpParameters(transceiver.getReceiver().getParameters()));
984
- transceiverUpdates.pushMap(transceiverUpdate);
985
- }
986
- return transceiverUpdates;
987
- }
988
-
989
- @ReactMethod
990
- public void mediaStreamTrackSetVideoEffects(String id, ReadableArray names) {
991
- ThreadUtils.runOnExecutor(() -> { getUserMediaImpl.setVideoEffects(id, names); });
992
- }
993
-
994
- @ReactMethod
995
- public void peerConnectionSetConfiguration(ReadableMap configuration, int id) {
996
- ThreadUtils.runOnExecutor(() -> {
997
- PeerConnection peerConnection = getPeerConnection(id);
998
- if (peerConnection == null) {
999
- Log.d(TAG, "peerConnectionSetConfiguration() peerConnection is null");
1000
- return;
1001
- }
1002
- peerConnection.setConfiguration(parseRTCConfiguration(configuration));
1003
- });
1004
- }
1005
-
1006
- @ReactMethod
1007
- public void peerConnectionCreateOffer(int id, ReadableMap options, Promise promise) {
1008
- ThreadUtils.runOnExecutor(() -> {
1009
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
1010
- PeerConnection peerConnection = pco.getPeerConnection();
1011
-
1012
- if (peerConnection == null) {
1013
- Log.d(TAG, "peerConnectionCreateOffer() peerConnection is null");
1014
- promise.reject(new Exception("PeerConnection not found"));
1015
- return;
1016
- }
1017
-
1018
- List<String> receiversIds = new ArrayList<>();
1019
- for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
1020
- receiversIds.add(transceiver.getReceiver().id());
1021
- }
1022
-
1023
- final SdpObserver observer = new SdpObserver() {
1024
- @Override
1025
- public void onCreateFailure(String s) {
1026
- ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1027
- }
1028
-
1029
- @Override
1030
- public void onCreateSuccess(SessionDescription sdp) {
1031
- ThreadUtils.runOnExecutor(() -> {
1032
- WritableMap params = Arguments.createMap();
1033
- WritableMap sdpInfo = Arguments.createMap();
1034
-
1035
- sdpInfo.putString("sdp", sdp.description);
1036
- sdpInfo.putString("type", sdp.type.canonicalForm());
1037
-
1038
- params.putArray("transceiversInfo", getTransceiversInfo(peerConnection));
1039
- params.putMap("sdpInfo", sdpInfo);
1040
-
1041
- WritableArray newTransceivers = Arguments.createArray();
1042
- for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
1043
- if (!receiversIds.contains(transceiver.getReceiver().id())) {
1044
- WritableMap newTransceiver = Arguments.createMap();
1045
- newTransceiver.putInt("transceiverOrder", pco.getNextTransceiverId());
1046
- newTransceiver.putMap(
1047
- "transceiver", SerializeUtils.serializeTransceiver(id, transceiver));
1048
- newTransceivers.pushMap(newTransceiver);
1049
- }
1050
- }
1051
-
1052
- params.putArray("newTransceivers", newTransceivers);
1053
-
1054
- promise.resolve(params);
1055
- });
1056
- }
1057
-
1058
- @Override
1059
- public void onSetFailure(String s) {}
1060
-
1061
- @Override
1062
- public void onSetSuccess() {}
1063
- };
1064
-
1065
- peerConnection.createOffer(observer, constraintsForOptions(options));
1066
- });
1067
- }
1068
-
1069
- @ReactMethod
1070
- public void peerConnectionCreateAnswer(int id, ReadableMap options, Promise promise) {
1071
- ThreadUtils.runOnExecutor(() -> {
1072
- PeerConnection peerConnection = getPeerConnection(id);
1073
-
1074
- if (peerConnection == null) {
1075
- Log.d(TAG, "peerConnectionCreateAnswer() peerConnection is null");
1076
- promise.reject(new Exception("PeerConnection not found"));
1077
- return;
1078
- }
1079
-
1080
- final SdpObserver observer = new SdpObserver() {
1081
- @Override
1082
- public void onCreateFailure(String s) {
1083
- ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1084
- }
1085
-
1086
- @Override
1087
- public void onCreateSuccess(SessionDescription sdp) {
1088
- ThreadUtils.runOnExecutor(() -> {
1089
- WritableMap params = Arguments.createMap();
1090
- WritableMap sdpInfo = Arguments.createMap();
1091
-
1092
- sdpInfo.putString("sdp", sdp.description);
1093
- sdpInfo.putString("type", sdp.type.canonicalForm());
1094
-
1095
- params.putArray("transceiversInfo", getTransceiversInfo(peerConnection));
1096
- params.putMap("sdpInfo", sdpInfo);
1097
-
1098
- promise.resolve(params);
1099
- });
1100
- }
1101
-
1102
- @Override
1103
- public void onSetFailure(String s) {}
1104
-
1105
- @Override
1106
- public void onSetSuccess() {}
1107
- };
1108
-
1109
- peerConnection.createAnswer(observer, constraintsForOptions(options));
1110
- });
1111
- }
1112
-
1113
- @ReactMethod
1114
- public void peerConnectionSetLocalDescription(int pcId, ReadableMap desc, Promise promise) {
1115
- ThreadUtils.runOnExecutor(() -> {
1116
- PeerConnection peerConnection = getPeerConnection(pcId);
1117
- if (peerConnection == null) {
1118
- Log.d(TAG, "peerConnectionSetLocalDescription() peerConnection is null");
1119
- promise.reject(new Exception("PeerConnection not found"));
1120
- return;
1121
- }
1122
-
1123
- final SdpObserver observer = new SdpObserver() {
1124
- @Override
1125
- public void onCreateSuccess(SessionDescription sdp) {}
1126
-
1127
- @Override
1128
- public void onSetSuccess() {
1129
- ThreadUtils.runOnExecutor(() -> {
1130
- WritableMap newSdpMap = Arguments.createMap();
1131
- WritableMap params = Arguments.createMap();
1132
-
1133
- SessionDescription newSdp = peerConnection.getLocalDescription();
1134
- // Can happen when doing a rollback.
1135
- if (newSdp != null) {
1136
- newSdpMap.putString("type", newSdp.type.canonicalForm());
1137
- newSdpMap.putString("sdp", newSdp.description);
1138
- }
1139
-
1140
- params.putMap("sdpInfo", newSdpMap);
1141
- params.putArray("transceiversInfo", getTransceiversInfo(peerConnection));
1142
-
1143
- promise.resolve(params);
1144
- });
1145
- }
1146
-
1147
- @Override
1148
- public void onCreateFailure(String s) {}
1149
-
1150
- @Override
1151
- public void onSetFailure(String s) {
1152
- ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1153
- }
1154
- };
1155
-
1156
- if (desc != null) {
1157
- SessionDescription sdp = new SessionDescription(
1158
- SessionDescription.Type.fromCanonicalForm(Objects.requireNonNull(desc.getString("type"))),
1159
- desc.getString("sdp"));
1160
-
1161
- peerConnection.setLocalDescription(observer, sdp);
1162
- } else {
1163
- peerConnection.setLocalDescription(observer);
1164
- }
1165
- });
1166
- }
1167
-
1168
- @ReactMethod
1169
- public void peerConnectionSetRemoteDescription(int id, ReadableMap desc, Promise promise) {
1170
- ThreadUtils.runOnExecutor(() -> {
1171
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
1172
- PeerConnection peerConnection = pco.getPeerConnection();
1173
-
1174
- if (peerConnection == null) {
1175
- Log.d(TAG, "peerConnectionSetRemoteDescription() peerConnection is null");
1176
- promise.reject(new Exception("PeerConnection not found"));
1177
- return;
1178
- }
1179
-
1180
- SessionDescription sdp = new SessionDescription(
1181
- SessionDescription.Type.fromCanonicalForm(desc.getString("type")), desc.getString("sdp"));
1182
-
1183
- List<String> receiversIds = new ArrayList<>();
1184
- for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
1185
- receiversIds.add(transceiver.getReceiver().id());
1186
- }
1187
-
1188
- final SdpObserver observer = new SdpObserver() {
1189
- @Override
1190
- public void onCreateSuccess(final SessionDescription sdp) {}
1191
-
1192
- @Override
1193
- public void onSetSuccess() {
1194
- ThreadUtils.runOnExecutor(() -> {
1195
- WritableMap newSdpMap = Arguments.createMap();
1196
- WritableMap params = Arguments.createMap();
1197
-
1198
- SessionDescription newSdp = peerConnection.getRemoteDescription();
1199
- // Be defensive for the rollback cases.
1200
- if (newSdp != null) {
1201
- newSdpMap.putString("type", newSdp.type.canonicalForm());
1202
- newSdpMap.putString("sdp", newSdp.description);
1203
- }
1204
-
1205
- params.putArray("transceiversInfo", getTransceiversInfo(peerConnection));
1206
- params.putMap("sdpInfo", newSdpMap);
1207
-
1208
- WritableArray newTransceivers = Arguments.createArray();
1209
- for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
1210
- if (!receiversIds.contains(transceiver.getReceiver().id())) {
1211
- WritableMap newTransceiver = Arguments.createMap();
1212
- newTransceiver.putInt("transceiverOrder", pco.getNextTransceiverId());
1213
- newTransceiver.putMap(
1214
- "transceiver", SerializeUtils.serializeTransceiver(id, transceiver));
1215
- newTransceivers.pushMap(newTransceiver);
1216
- }
1217
- }
1218
-
1219
- params.putArray("newTransceivers", newTransceivers);
1220
-
1221
- promise.resolve(params);
1222
- });
1223
- }
1224
-
1225
- @Override
1226
- public void onCreateFailure(String s) {}
1227
-
1228
- @Override
1229
- public void onSetFailure(String s) {
1230
- ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1231
- }
1232
- };
1233
-
1234
- peerConnection.setRemoteDescription(observer, sdp);
1235
- });
1236
- }
1237
-
1238
- @ReactMethod(isBlockingSynchronousMethod = true)
1239
- public WritableMap receiverGetCapabilities(String kind) {
1240
- try {
1241
- return (WritableMap) ThreadUtils
1242
- .submitToExecutor((Callable<Object>) () -> {
1243
- MediaStreamTrack.MediaType mediaType;
1244
- if (kind.equals("audio")) {
1245
- mediaType = MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO;
1246
- } else if (kind.equals("video")) {
1247
- mediaType = MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO;
1248
- } else {
1249
- return Arguments.createMap();
1250
- }
1251
-
1252
- RtpCapabilities capabilities = mFactory.getRtpReceiverCapabilities(mediaType);
1253
- return SerializeUtils.serializeRtpCapabilities(capabilities);
1254
- })
1255
- .get();
1256
- } catch (ExecutionException | InterruptedException e) {
1257
- Log.d(TAG, "receiverGetCapabilities() " + e.getMessage());
1258
- return null;
1259
- }
1260
- }
1261
-
1262
- @ReactMethod(isBlockingSynchronousMethod = true)
1263
- public WritableMap senderGetCapabilities(String kind) {
1264
- try {
1265
- return (WritableMap) ThreadUtils
1266
- .submitToExecutor((Callable<Object>) () -> {
1267
- MediaStreamTrack.MediaType mediaType;
1268
- if (kind.equals("audio")) {
1269
- mediaType = MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO;
1270
- } else if (kind.equals("video")) {
1271
- mediaType = MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO;
1272
- } else {
1273
- return Arguments.createMap();
1274
- }
1275
-
1276
- RtpCapabilities capabilities = mFactory.getRtpSenderCapabilities(mediaType);
1277
- return SerializeUtils.serializeRtpCapabilities(capabilities);
1278
- })
1279
- .get();
1280
- } catch (ExecutionException | InterruptedException e) {
1281
- Log.d(TAG, "senderGetCapabilities() " + e.getMessage());
1282
- return null;
1283
- }
1284
- }
1285
-
1286
- @ReactMethod
1287
- public void receiverGetStats(int pcId, String receiverId, Promise promise) {
1288
- ThreadUtils.runOnExecutor(() -> {
1289
- PeerConnectionObserver pco = mPeerConnectionObservers.get(pcId);
1290
- if (pco == null || pco.getPeerConnection() == null) {
1291
- Log.d(TAG, "receiverGetStats() peerConnection is null");
1292
- promise.resolve(StringUtils.statsToJSON(new RTCStatsReport(0, new HashMap<>())));
1293
- } else {
1294
- pco.receiverGetStats(receiverId, promise);
1295
- }
1296
- });
1297
- }
1298
-
1299
- @ReactMethod
1300
- public void senderGetStats(int pcId, String senderId, Promise promise) {
1301
- ThreadUtils.runOnExecutor(() -> {
1302
- PeerConnectionObserver pco = mPeerConnectionObservers.get(pcId);
1303
- if (pco == null || pco.getPeerConnection() == null) {
1304
- Log.d(TAG, "senderGetStats() peerConnection is null");
1305
- promise.resolve(StringUtils.statsToJSON(new RTCStatsReport(0, new HashMap<>())));
1306
- } else {
1307
- pco.senderGetStats(senderId, promise);
1308
- }
1309
- });
1310
- }
1311
-
1312
- @ReactMethod
1313
- public void peerConnectionAddICECandidate(int pcId, ReadableMap candidateMap, Promise promise) {
1314
- ThreadUtils.runOnExecutor(() -> {
1315
- PeerConnection peerConnection = getPeerConnection(pcId);
1316
- if (peerConnection == null) {
1317
- Log.d(TAG, "peerConnectionAddICECandidate() peerConnection is null");
1318
- promise.reject(new Exception("PeerConnection not found"));
1319
- return;
1320
- }
1321
-
1322
- if (!candidateMap.hasKey("sdpMid") && !candidateMap.hasKey("sdpMLineIndex")) {
1323
- promise.reject("E_TYPE_ERROR", "Invalid argument");
1324
- return;
1325
- }
1326
-
1327
- IceCandidate candidate = new IceCandidate(candidateMap.hasKey("sdpMid") && !candidateMap.isNull("sdpMid")
1328
- ? candidateMap.getString("sdpMid")
1329
- : "",
1330
- candidateMap.hasKey("sdpMLineIndex") && !candidateMap.isNull("sdpMLineIndex")
1331
- ? candidateMap.getInt("sdpMLineIndex")
1332
- : 0,
1333
- candidateMap.getString("candidate"));
1334
-
1335
- peerConnection.addIceCandidate(candidate, new AddIceObserver() {
1336
- @Override
1337
- public void onAddSuccess() {
1338
- ThreadUtils.runOnExecutor(() -> {
1339
- WritableMap newSdpMap = Arguments.createMap();
1340
- SessionDescription newSdp = peerConnection.getRemoteDescription();
1341
- newSdpMap.putString("type", newSdp.type.canonicalForm());
1342
- newSdpMap.putString("sdp", newSdp.description);
1343
- promise.resolve(newSdpMap);
1344
- });
1345
- }
1346
-
1347
- @Override
1348
- public void onAddFailure(String s) {
1349
- ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1350
- }
1351
- });
1352
- });
1353
- }
1354
-
1355
- @ReactMethod
1356
- public void peerConnectionGetStats(int peerConnectionId, Promise promise) {
1357
- ThreadUtils.runOnExecutor(() -> {
1358
- PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1359
- if (pco == null || pco.getPeerConnection() == null) {
1360
- Log.d(TAG, "peerConnectionGetStats() peerConnection is null");
1361
- promise.resolve(StringUtils.statsToJSON(new RTCStatsReport(0, new HashMap<>())));
1362
- } else {
1363
- pco.getStats(promise);
1364
- }
1365
- });
1366
- }
1367
-
1368
- @ReactMethod
1369
- public void peerConnectionClose(int id) {
1370
- ThreadUtils.runOnExecutor(() -> {
1371
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
1372
- if (pco == null || pco.getPeerConnection() == null) {
1373
- Log.d(TAG, "peerConnectionClose() peerConnection is null");
1374
- return;
1375
- }
1376
- pco.close();
1377
- });
1378
- }
1379
-
1380
- @ReactMethod
1381
- public void peerConnectionDispose(int id) {
1382
- ThreadUtils.runOnExecutor(() -> {
1383
- PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
1384
- if (pco == null || pco.getPeerConnection() == null) {
1385
- Log.d(TAG, "peerConnectionDispose() peerConnection is null");
1386
- }
1387
- pco.dispose();
1388
- mPeerConnectionObservers.remove(id);
1389
- });
1390
- }
1391
-
1392
- @ReactMethod
1393
- public void peerConnectionRestartIce(int pcId) {
1394
- ThreadUtils.runOnExecutor(() -> {
1395
- PeerConnection peerConnection = getPeerConnection(pcId);
1396
- if (peerConnection == null) {
1397
- Log.w(TAG, "peerConnectionRestartIce() peerConnection is null");
1398
- return;
1399
- }
1400
-
1401
- peerConnection.restartIce();
1402
- });
1403
- }
1404
-
1405
- @ReactMethod(isBlockingSynchronousMethod = true)
1406
- public WritableMap createDataChannel(int peerConnectionId, String label, ReadableMap config) {
1407
- try {
1408
- return (WritableMap) ThreadUtils
1409
- .submitToExecutor((Callable<Object>) () -> {
1410
- PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1411
- if (pco == null || pco.getPeerConnection() == null) {
1412
- Log.d(TAG, "createDataChannel() peerConnection is null");
1413
- return null;
1414
- } else {
1415
- return pco.createDataChannel(label, config);
1416
- }
1417
- })
1418
- .get();
1419
- } catch (ExecutionException | InterruptedException e) {
1420
- return null;
1421
- }
1422
- }
1423
-
1424
- @ReactMethod
1425
- public void dataChannelClose(int peerConnectionId, String reactTag) {
1426
- ThreadUtils.runOnExecutor(() -> {
1427
- // Forward to PeerConnectionObserver which deals with DataChannels
1428
- // because DataChannel is owned by PeerConnection.
1429
- PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1430
- if (pco == null || pco.getPeerConnection() == null) {
1431
- Log.d(TAG, "dataChannelClose() peerConnection is null");
1432
- return;
1433
- }
1434
-
1435
- pco.dataChannelClose(reactTag);
1436
- });
1437
- }
1438
-
1439
- @ReactMethod
1440
- public void dataChannelDispose(int peerConnectionId, String reactTag) {
1441
- ThreadUtils.runOnExecutor(() -> {
1442
- PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1443
- if (pco == null || pco.getPeerConnection() == null) {
1444
- Log.d(TAG, "dataChannelDispose() peerConnection is null");
1445
- return;
1446
- }
1447
-
1448
- pco.dataChannelDispose(reactTag);
1449
- });
1450
- }
1451
-
1452
- @ReactMethod
1453
- public void dataChannelSend(int peerConnectionId, String reactTag, String data, String type) {
1454
- ThreadUtils.runOnExecutor(() -> {
1455
- // Forward to PeerConnectionObserver which deals with DataChannels
1456
- // because DataChannel is owned by PeerConnection.
1457
- PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1458
- if (pco == null || pco.getPeerConnection() == null) {
1459
- Log.d(TAG, "dataChannelSend() peerConnection is null");
1460
- return;
1461
- }
1462
-
1463
- pco.dataChannelSend(reactTag, data, type);
1464
- });
1465
- }
1466
-
1467
- // Frame Cryptor methods
1468
- ////////////////////////////////
1469
- RTCCryptoManager frameCryptor = new RTCCryptoManager(this);
1470
-
1471
- @ReactMethod(isBlockingSynchronousMethod = true)
1472
- public String frameCryptorFactoryCreateFrameCryptor(ReadableMap config) {
1473
- return frameCryptor.frameCryptorFactoryCreateFrameCryptor(config);
1474
- }
1475
-
1476
- @ReactMethod
1477
- public void frameCryptorSetKeyIndex(ReadableMap config, Promise promise) {
1478
- frameCryptor.frameCryptorSetKeyIndex(config, promise);
1479
- }
1480
-
1481
- @ReactMethod
1482
- public void frameCryptorGetKeyIndex(ReadableMap config, Promise promise) {
1483
- frameCryptor.frameCryptorGetKeyIndex(config, promise);
1484
- }
1485
-
1486
- @ReactMethod
1487
- public void frameCryptorSetEnabled(ReadableMap config, Promise promise) {
1488
- frameCryptor.frameCryptorSetEnabled(config, promise);
1489
- }
1490
-
1491
- @ReactMethod
1492
- public void frameCryptorGetEnabled(ReadableMap config, Promise promise) {
1493
- frameCryptor.frameCryptorGetEnabled(config, promise);
1494
- }
1495
-
1496
- @ReactMethod
1497
- public void frameCryptorDispose(ReadableMap config, Promise promise) {
1498
- frameCryptor.frameCryptorDispose(config, promise);
1499
- }
1500
-
1501
- @ReactMethod(isBlockingSynchronousMethod = true)
1502
- public String frameCryptorFactoryCreateKeyProvider(ReadableMap config) {
1503
- return frameCryptor.frameCryptorFactoryCreateKeyProvider(config);
1504
- }
1505
-
1506
- @ReactMethod
1507
- public void keyProviderSetSharedKey(ReadableMap config, Promise promise) {
1508
- frameCryptor.keyProviderSetSharedKey(config, promise);
1509
- }
1510
-
1511
- @ReactMethod
1512
- public void keyProviderRatchetSharedKey(ReadableMap config, Promise promise) {
1513
- frameCryptor.keyProviderRatchetSharedKey(config, promise);
1514
- }
1515
-
1516
- @ReactMethod
1517
- public void keyProviderExportSharedKey(ReadableMap config, Promise promise) {
1518
- frameCryptor.keyProviderExportSharedKey(config, promise);
1519
- }
1520
-
1521
- @ReactMethod
1522
- public void keyProviderSetKey(ReadableMap config, Promise promise) {
1523
- frameCryptor.keyProviderSetKey(config, promise);
1524
- }
1525
-
1526
- @ReactMethod
1527
- public void keyProviderRatchetKey(ReadableMap config, Promise promise) {
1528
- frameCryptor.keyProviderRatchetKey(config, promise);
1529
- }
1530
-
1531
- @ReactMethod
1532
- public void keyProviderExportKey(ReadableMap config, Promise promise) {
1533
- frameCryptor.keyProviderExportKey(config, promise);
1534
- }
1535
-
1536
- @ReactMethod
1537
- public void keyProviderSetSifTrailer(ReadableMap config, Promise promise) {
1538
- frameCryptor.keyProviderSetSifTrailer(config, promise);
1539
- }
1540
-
1541
- @ReactMethod
1542
- public void keyProviderDispose(ReadableMap config, Promise promise) {
1543
- frameCryptor.keyProviderDispose(config, promise);
1544
- }
1545
-
1546
- @ReactMethod
1547
- public void dataPacketCryptorFactoryCreateDataPacketCryptor(ReadableMap params, @NonNull Promise result) {
1548
- frameCryptor.dataPacketCryptorFactoryCreateDataPacketCryptor(params, result);
1549
- }
1550
-
1551
- @ReactMethod
1552
- public void dataPacketCryptorEncrypt(ReadableMap params, @NonNull Promise result) {
1553
- frameCryptor.dataPacketCryptorEncrypt(params, result);
1554
- }
1555
-
1556
- @ReactMethod
1557
- public void dataPacketCryptorDecrypt(ReadableMap params, @NonNull Promise result) {
1558
- frameCryptor.dataPacketCryptorDecrypt(params, result);
1559
- }
1560
-
1561
- @ReactMethod
1562
- public void dataPacketCryptorDispose(ReadableMap params, @NonNull Promise result) {
1563
- frameCryptor.dataPacketCryptorDispose(params, result);
1564
- }
1565
-
1566
- @ReactMethod
1567
- public void addListener(String eventName) {
1568
- // Keep: Required for RN built in Event Emitter Calls.
1569
- }
1570
-
1571
- @ReactMethod
1572
- public void removeListeners(Integer count) {
1573
- // Keep: Required for RN built in Event Emitter Calls.
1574
- }
1575
-
1576
- @ReactMethod
1577
- public void startPalabraTranslation(int peerConnectionId, String trackId, String clientId,
1578
- String clientSecret, String sourceLang, String targetLang,
1579
- String apiUrl, Promise promise) {
1580
- PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1581
- if (pco == null) {
1582
- promise.reject("E_INVALID", "pc_not_found");
1583
- return;
1584
- }
1585
-
1586
- MediaStreamTrack track = pco.remoteTracks.get(trackId);
1587
- if (track == null) {
1588
- promise.reject("E_INVALID", "track_not_found");
1589
- return;
1590
- }
1591
-
1592
- if (!(track instanceof AudioTrack)) {
1593
- promise.reject("E_INVALID", "not_audio_track");
1594
- return;
1595
- }
1596
-
1597
- AudioTrack audioTrack = (AudioTrack) track;
1598
-
1599
- if (palabraClient != null) {
1600
- palabraClient.stop();
1601
- }
1602
-
1603
- PalabraConfig config = new PalabraConfig(clientId, clientSecret, sourceLang, targetLang, apiUrl);
1604
- palabraClient = new PalabraClient(getReactApplicationContext(), config);
1605
- palabraClient.setListener(new PalabraListener() {
1606
- @Override
1607
- public void onTranscription(String text, String lang, boolean isFinal) {
1608
- WritableMap params = Arguments.createMap();
1609
- params.putString("text", text);
1610
- params.putString("lang", lang);
1611
- params.putBoolean("isFinal", isFinal);
1612
- sendEvent("palabraTranscription", params);
1613
- }
1614
-
1615
- @Override
1616
- public void onConnectionState(String state) {
1617
- WritableMap params = Arguments.createMap();
1618
- params.putString("state", state);
1619
- sendEvent("palabraConnectionState", params);
1620
- }
1621
-
1622
- @Override
1623
- public void onError(int code, String message) {
1624
- WritableMap params = Arguments.createMap();
1625
- params.putInt("code", code);
1626
- params.putString("message", message);
1627
- sendEvent("palabraError", params);
1628
- }
1629
- });
1630
-
1631
- palabraClient.start(audioTrack);
1632
- promise.resolve(null);
1633
- }
1634
-
1635
- @ReactMethod
1636
- public void stopPalabraTranslation(Promise promise) {
1637
- if (palabraClient != null) {
1638
- palabraClient.stop();
1639
- palabraClient = null;
1640
- }
1641
- promise.resolve(null);
1642
- }
1643
- }
1
+ package com.oney.WebRTCModule;
2
+
3
+ import android.util.Log;
4
+ import android.util.Pair;
5
+ import android.util.SparseArray;
6
+
7
+ import androidx.annotation.NonNull;
8
+ import androidx.annotation.Nullable;
9
+
10
+ import com.facebook.react.bridge.Arguments;
11
+ import com.facebook.react.bridge.Callback;
12
+ import com.facebook.react.bridge.Promise;
13
+ import com.facebook.react.bridge.ReactApplicationContext;
14
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
15
+ import com.facebook.react.bridge.ReactMethod;
16
+ import com.facebook.react.bridge.ReadableArray;
17
+ import com.facebook.react.bridge.ReadableMap;
18
+ import com.facebook.react.bridge.ReadableMapKeySetIterator;
19
+ import com.facebook.react.bridge.ReadableType;
20
+ import com.facebook.react.bridge.WritableArray;
21
+ import com.facebook.react.bridge.WritableMap;
22
+ import com.facebook.react.module.annotations.ReactModule;
23
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
24
+ import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoDecoderFactory;
25
+ import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory;
26
+ import com.oney.WebRTCModule.palabra.PalabraClient;
27
+ import com.oney.WebRTCModule.palabra.PalabraConfig;
28
+ import com.oney.WebRTCModule.palabra.PalabraListener;
29
+
30
+ import org.webrtc.AddIceObserver;
31
+ import org.webrtc.AudioProcessingFactory;
32
+ import org.webrtc.AudioTrack;
33
+ import org.webrtc.CryptoOptions;
34
+ import org.webrtc.EglBase;
35
+ import org.webrtc.IceCandidate;
36
+ import org.webrtc.Loggable;
37
+ import org.webrtc.Logging;
38
+ import org.webrtc.MediaConstraints;
39
+ import org.webrtc.MediaStream;
40
+ import org.webrtc.MediaStreamTrack;
41
+ import org.webrtc.PeerConnection;
42
+ import org.webrtc.PeerConnectionFactory;
43
+ import org.webrtc.RTCStatsReport;
44
+ import org.webrtc.RtpCapabilities;
45
+ import org.webrtc.RtpParameters;
46
+ import org.webrtc.RtpSender;
47
+ import org.webrtc.RtpTransceiver;
48
+ import org.webrtc.SdpObserver;
49
+ import org.webrtc.SessionDescription;
50
+ import org.webrtc.SoftwareVideoDecoderFactory;
51
+ import org.webrtc.SoftwareVideoEncoderFactory;
52
+ import org.webrtc.VideoDecoderFactory;
53
+ import org.webrtc.VideoEncoderFactory;
54
+ import org.webrtc.VideoTrack;
55
+ import org.webrtc.audio.AudioDeviceModule;
56
+ import org.webrtc.audio.JavaAudioDeviceModule;
57
+
58
+ import java.util.ArrayList;
59
+ import java.util.HashMap;
60
+ import java.util.List;
61
+ import java.util.Map;
62
+ import java.util.Objects;
63
+ import java.util.concurrent.Callable;
64
+ import java.util.concurrent.ExecutionException;
65
+
66
+ @ReactModule(name = "WebRTCModule")
67
+ public class WebRTCModule extends ReactContextBaseJavaModule {
68
+ static final String TAG = WebRTCModule.class.getCanonicalName();
69
+
70
+ PeerConnectionFactory mFactory;
71
+ VideoEncoderFactory mVideoEncoderFactory;
72
+ VideoDecoderFactory mVideoDecoderFactory;
73
+ AudioDeviceModule mAudioDeviceModule;
74
+
75
+ // Need to expose the peer connection codec factories here to get capabilities
76
+ private final SparseArray<PeerConnectionObserver> mPeerConnectionObservers;
77
+ final Map<String, MediaStream> localStreams;
78
+
79
+ private final GetUserMediaImpl getUserMediaImpl;
80
+
81
+ private PalabraClient palabraClient;
82
+
83
+ public WebRTCModule(ReactApplicationContext reactContext) {
84
+ super(reactContext);
85
+
86
+ mPeerConnectionObservers = new SparseArray<>();
87
+ localStreams = new HashMap<>();
88
+
89
+ WebRTCModuleOptions options = WebRTCModuleOptions.getInstance();
90
+
91
+ AudioDeviceModule adm = options.audioDeviceModule;
92
+ VideoEncoderFactory encoderFactory = options.videoEncoderFactory;
93
+ VideoDecoderFactory decoderFactory = options.videoDecoderFactory;
94
+ Loggable injectableLogger = options.injectableLogger;
95
+ Logging.Severity loggingSeverity = options.loggingSeverity;
96
+ String fieldTrials = options.fieldTrials;
97
+
98
+ PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(reactContext)
99
+ .setFieldTrials(fieldTrials)
100
+ .setNativeLibraryLoader(new LibraryLoader())
101
+ .setInjectableLogger(injectableLogger, loggingSeverity)
102
+ .createInitializationOptions());
103
+
104
+ if (injectableLogger == null && loggingSeverity != null) {
105
+ Logging.enableLogToDebugOutput(loggingSeverity);
106
+ }
107
+
108
+ if (encoderFactory == null || decoderFactory == null) {
109
+ // Initialize EGL context required for HW acceleration.
110
+ EglBase.Context eglContext = EglUtils.getRootEglBaseContext();
111
+
112
+ if (eglContext != null) {
113
+ encoderFactory = new H264AndSoftwareVideoEncoderFactory(eglContext);
114
+ decoderFactory = new H264AndSoftwareVideoDecoderFactory(eglContext);
115
+ } else {
116
+ encoderFactory = new SoftwareVideoEncoderFactory();
117
+ decoderFactory = new SoftwareVideoDecoderFactory();
118
+ }
119
+ }
120
+
121
+ if (adm == null) {
122
+ adm = JavaAudioDeviceModule.builder(reactContext).createAudioDeviceModule();
123
+ }
124
+
125
+ AudioProcessingFactory audioProcessingFactory = null;
126
+ try {
127
+ if (options.audioProcessingFactoryFactory != null) {
128
+ audioProcessingFactory = options.audioProcessingFactoryFactory.call();
129
+ }
130
+ } catch (Exception e) {
131
+ // do nothing.
132
+ }
133
+
134
+ Log.d(TAG, "Using video encoder factory: " + encoderFactory.getClass().getCanonicalName());
135
+ Log.d(TAG, "Using video decoder factory: " + decoderFactory.getClass().getCanonicalName());
136
+
137
+ PeerConnectionFactory.Builder pcFactoryBuilder = PeerConnectionFactory.builder()
138
+ .setAudioDeviceModule(adm)
139
+ .setVideoEncoderFactory(encoderFactory)
140
+ .setVideoDecoderFactory(decoderFactory);
141
+
142
+ if (audioProcessingFactory != null) {
143
+ pcFactoryBuilder.setAudioProcessingFactory(audioProcessingFactory);
144
+ }
145
+
146
+ mFactory = pcFactoryBuilder.createPeerConnectionFactory();
147
+
148
+ // PeerConnectionFactory now owns the adm native pointer, and we don't need it anymore.
149
+ adm.release();
150
+
151
+ // Saving the encoder and decoder factories to get codec info later when needed.
152
+ mVideoEncoderFactory = encoderFactory;
153
+ mVideoDecoderFactory = decoderFactory;
154
+ mAudioDeviceModule = adm;
155
+
156
+ getUserMediaImpl = new GetUserMediaImpl(this, reactContext);
157
+ }
158
+
159
+ @NonNull
160
+ @Override
161
+ public String getName() {
162
+ return "WebRTCModule";
163
+ }
164
+
165
+ public PeerConnectionObserver getPeerConnectionObserver(int id) {
166
+ return mPeerConnectionObservers.get(id);
167
+ }
168
+ private PeerConnection getPeerConnection(int id) {
169
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
170
+ return (pco == null) ? null : pco.getPeerConnection();
171
+ }
172
+
173
+ void sendEvent(String eventName, @Nullable ReadableMap params) {
174
+ getReactApplicationContext()
175
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
176
+ .emit(eventName, params);
177
+ }
178
+
179
+ private PeerConnection.IceServer createIceServer(String url) {
180
+ return PeerConnection.IceServer.builder(url).createIceServer();
181
+ }
182
+
183
+ private PeerConnection.IceServer createIceServer(String url, String username, String credential) {
184
+ return PeerConnection.IceServer.builder(url).setUsername(username).setPassword(credential).createIceServer();
185
+ }
186
+
187
+ private List<PeerConnection.IceServer> createIceServers(ReadableArray iceServersArray) {
188
+ final int size = (iceServersArray == null) ? 0 : iceServersArray.size();
189
+ List<PeerConnection.IceServer> iceServers = new ArrayList<>(size);
190
+ for (int i = 0; i < size; i++) {
191
+ ReadableMap iceServerMap = iceServersArray.getMap(i);
192
+ boolean hasUsernameAndCredential = iceServerMap.hasKey("username") && iceServerMap.hasKey("credential");
193
+ if (iceServerMap.hasKey("urls")) {
194
+ switch (iceServerMap.getType("urls")) {
195
+ case String:
196
+ if (hasUsernameAndCredential) {
197
+ iceServers.add(createIceServer(iceServerMap.getString("urls"),
198
+ iceServerMap.getString("username"),
199
+ iceServerMap.getString("credential")));
200
+ } else {
201
+ iceServers.add(createIceServer(iceServerMap.getString("urls")));
202
+ }
203
+ break;
204
+ case Array:
205
+ ReadableArray urls = iceServerMap.getArray("urls");
206
+ for (int j = 0; j < urls.size(); j++) {
207
+ String url = urls.getString(j);
208
+ if (hasUsernameAndCredential) {
209
+ iceServers.add(createIceServer(
210
+ url, iceServerMap.getString("username"), iceServerMap.getString("credential")));
211
+ } else {
212
+ iceServers.add(createIceServer(url));
213
+ }
214
+ }
215
+ break;
216
+ }
217
+ }
218
+ }
219
+ return iceServers;
220
+ }
221
+
222
+ private PeerConnection.RTCConfiguration parseRTCConfiguration(ReadableMap map) {
223
+ ReadableArray iceServersArray = null;
224
+ if (map != null && map.hasKey("iceServers")) {
225
+ iceServersArray = map.getArray("iceServers");
226
+ }
227
+ List<PeerConnection.IceServer> iceServers = createIceServers(iceServersArray);
228
+
229
+ PeerConnection.RTCConfiguration conf = new PeerConnection.RTCConfiguration(iceServers);
230
+ conf.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
231
+
232
+ // Required for perfect negotiation.
233
+ conf.enableImplicitRollback = true;
234
+
235
+ // Enable GCM ciphers.
236
+ CryptoOptions cryptoOptions = CryptoOptions.builder()
237
+ .setEnableGcmCryptoSuites(true)
238
+ .setEnableAes128Sha1_32CryptoCipher(false)
239
+ .setEnableEncryptedRtpHeaderExtensions(false)
240
+ .setRequireFrameEncryption(false)
241
+ .createCryptoOptions();
242
+ conf.cryptoOptions = cryptoOptions;
243
+
244
+ if (map == null) {
245
+ return conf;
246
+ }
247
+
248
+ // iceTransportPolicy (public api)
249
+ if (map.hasKey("iceTransportPolicy") && map.getType("iceTransportPolicy") == ReadableType.String) {
250
+ final String v = map.getString("iceTransportPolicy");
251
+ if (v != null) {
252
+ switch (v) {
253
+ case "all": // public
254
+ conf.iceTransportsType = PeerConnection.IceTransportsType.ALL;
255
+ break;
256
+ case "relay": // public
257
+ conf.iceTransportsType = PeerConnection.IceTransportsType.RELAY;
258
+ break;
259
+ case "nohost":
260
+ conf.iceTransportsType = PeerConnection.IceTransportsType.NOHOST;
261
+ break;
262
+ case "none":
263
+ conf.iceTransportsType = PeerConnection.IceTransportsType.NONE;
264
+ break;
265
+ }
266
+ }
267
+ }
268
+
269
+ // bundlePolicy (public api)
270
+ if (map.hasKey("bundlePolicy") && map.getType("bundlePolicy") == ReadableType.String) {
271
+ final String v = map.getString("bundlePolicy");
272
+ if (v != null) {
273
+ switch (v) {
274
+ case "balanced": // public
275
+ conf.bundlePolicy = PeerConnection.BundlePolicy.BALANCED;
276
+ break;
277
+ case "max-compat": // public
278
+ conf.bundlePolicy = PeerConnection.BundlePolicy.MAXCOMPAT;
279
+ break;
280
+ case "max-bundle": // public
281
+ conf.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE;
282
+ break;
283
+ }
284
+ }
285
+ }
286
+
287
+ // rtcpMuxPolicy (public api)
288
+ if (map.hasKey("rtcpMuxPolicy") && map.getType("rtcpMuxPolicy") == ReadableType.String) {
289
+ final String v = map.getString("rtcpMuxPolicy");
290
+ if (v != null) {
291
+ switch (v) {
292
+ case "negotiate": // public
293
+ conf.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.NEGOTIATE;
294
+ break;
295
+ case "require": // public
296
+ conf.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE;
297
+ break;
298
+ }
299
+ }
300
+ }
301
+
302
+ // FIXME: peerIdentity of type DOMString (public api)
303
+ // FIXME: certificates of type sequence<RTCCertificate> (public api)
304
+
305
+ // iceCandidatePoolSize of type unsigned short, defaulting to 0
306
+ if (map.hasKey("iceCandidatePoolSize") && map.getType("iceCandidatePoolSize") == ReadableType.Number) {
307
+ final int v = map.getInt("iceCandidatePoolSize");
308
+ if (v > 0) {
309
+ conf.iceCandidatePoolSize = v;
310
+ }
311
+ }
312
+
313
+ // === below is private api in webrtc ===
314
+
315
+ // tcpCandidatePolicy (private api)
316
+ if (map.hasKey("tcpCandidatePolicy") && map.getType("tcpCandidatePolicy") == ReadableType.String) {
317
+ final String v = map.getString("tcpCandidatePolicy");
318
+ if (v != null) {
319
+ switch (v) {
320
+ case "enabled":
321
+ conf.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.ENABLED;
322
+ break;
323
+ case "disabled":
324
+ conf.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
325
+ break;
326
+ }
327
+ }
328
+ }
329
+
330
+ // candidateNetworkPolicy (private api)
331
+ if (map.hasKey("candidateNetworkPolicy") && map.getType("candidateNetworkPolicy") == ReadableType.String) {
332
+ final String v = map.getString("candidateNetworkPolicy");
333
+ if (v != null) {
334
+ switch (v) {
335
+ case "all":
336
+ conf.candidateNetworkPolicy = PeerConnection.CandidateNetworkPolicy.ALL;
337
+ break;
338
+ case "low_cost":
339
+ conf.candidateNetworkPolicy = PeerConnection.CandidateNetworkPolicy.LOW_COST;
340
+ break;
341
+ }
342
+ }
343
+ }
344
+
345
+ // KeyType (private api)
346
+ if (map.hasKey("keyType") && map.getType("keyType") == ReadableType.String) {
347
+ final String v = map.getString("keyType");
348
+ if (v != null) {
349
+ switch (v) {
350
+ case "RSA":
351
+ conf.keyType = PeerConnection.KeyType.RSA;
352
+ break;
353
+ case "ECDSA":
354
+ conf.keyType = PeerConnection.KeyType.ECDSA;
355
+ break;
356
+ }
357
+ }
358
+ }
359
+
360
+ // continualGatheringPolicy (private api)
361
+ if (map.hasKey("continualGatheringPolicy") && map.getType("continualGatheringPolicy") == ReadableType.String) {
362
+ final String v = map.getString("continualGatheringPolicy");
363
+ if (v != null) {
364
+ switch (v) {
365
+ case "gather_once":
366
+ conf.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_ONCE;
367
+ break;
368
+ case "gather_continually":
369
+ conf.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY;
370
+ break;
371
+ }
372
+ }
373
+ }
374
+
375
+ // audioJitterBufferMaxPackets (private api)
376
+ if (map.hasKey("audioJitterBufferMaxPackets")
377
+ && map.getType("audioJitterBufferMaxPackets") == ReadableType.Number) {
378
+ final int v = map.getInt("audioJitterBufferMaxPackets");
379
+ if (v > 0) {
380
+ conf.audioJitterBufferMaxPackets = v;
381
+ }
382
+ }
383
+
384
+ // iceConnectionReceivingTimeout (private api)
385
+ if (map.hasKey("iceConnectionReceivingTimeout")
386
+ && map.getType("iceConnectionReceivingTimeout") == ReadableType.Number) {
387
+ final int v = map.getInt("iceConnectionReceivingTimeout");
388
+ conf.iceConnectionReceivingTimeout = v;
389
+ }
390
+
391
+ // iceBackupCandidatePairPingInterval (private api)
392
+ if (map.hasKey("iceBackupCandidatePairPingInterval")
393
+ && map.getType("iceBackupCandidatePairPingInterval") == ReadableType.Number) {
394
+ final int v = map.getInt("iceBackupCandidatePairPingInterval");
395
+ conf.iceBackupCandidatePairPingInterval = v;
396
+ }
397
+
398
+ // audioJitterBufferFastAccelerate (private api)
399
+ if (map.hasKey("audioJitterBufferFastAccelerate")
400
+ && map.getType("audioJitterBufferFastAccelerate") == ReadableType.Boolean) {
401
+ final boolean v = map.getBoolean("audioJitterBufferFastAccelerate");
402
+ conf.audioJitterBufferFastAccelerate = v;
403
+ }
404
+
405
+ // pruneTurnPorts (private api)
406
+ if (map.hasKey("pruneTurnPorts") && map.getType("pruneTurnPorts") == ReadableType.Boolean) {
407
+ final boolean v = map.getBoolean("pruneTurnPorts");
408
+ conf.pruneTurnPorts = v;
409
+ }
410
+
411
+ // presumeWritableWhenFullyRelayed (private api)
412
+ if (map.hasKey("presumeWritableWhenFullyRelayed")
413
+ && map.getType("presumeWritableWhenFullyRelayed") == ReadableType.Boolean) {
414
+ final boolean v = map.getBoolean("presumeWritableWhenFullyRelayed");
415
+ conf.presumeWritableWhenFullyRelayed = v;
416
+ }
417
+
418
+ return conf;
419
+ }
420
+
421
+ @ReactMethod(isBlockingSynchronousMethod = true)
422
+ public boolean peerConnectionInit(ReadableMap configuration, int id) {
423
+ PeerConnection.RTCConfiguration rtcConfiguration = parseRTCConfiguration(configuration);
424
+
425
+ try {
426
+ return (boolean) ThreadUtils
427
+ .submitToExecutor(() -> {
428
+ PeerConnectionObserver observer = new PeerConnectionObserver(this, id);
429
+ PeerConnection peerConnection = mFactory.createPeerConnection(rtcConfiguration, observer);
430
+ if (peerConnection == null) {
431
+ return false;
432
+ }
433
+ observer.setPeerConnection(peerConnection);
434
+ mPeerConnectionObservers.put(id, observer);
435
+ return true;
436
+ })
437
+ .get();
438
+ } catch (ExecutionException | InterruptedException e) {
439
+ e.printStackTrace();
440
+ throw new RuntimeException(e);
441
+ }
442
+ }
443
+
444
+ MediaStream getStreamForReactTag(String streamReactTag) {
445
+ // This function _only_ gets called from WebRTCView, in the UI thread.
446
+ // Hence make sure we run this code in the executor or we run at the risk
447
+ // of being out of sync.
448
+ try {
449
+ return (MediaStream) ThreadUtils
450
+ .submitToExecutor((Callable<Object>) () -> {
451
+ MediaStream stream = localStreams.get(streamReactTag);
452
+
453
+ if (stream != null) {
454
+ return stream;
455
+ }
456
+
457
+ for (int i = 0, size = mPeerConnectionObservers.size(); i < size; i++) {
458
+ PeerConnectionObserver pco = mPeerConnectionObservers.valueAt(i);
459
+ stream = pco.remoteStreams.get(streamReactTag);
460
+ if (stream != null) {
461
+ return stream;
462
+ }
463
+ }
464
+
465
+ return null;
466
+ })
467
+ .get();
468
+ } catch (ExecutionException | InterruptedException e) {
469
+ return null;
470
+ }
471
+ }
472
+
473
+ public MediaStreamTrack getTrack(int pcId, String trackId) {
474
+ if (pcId == -1) {
475
+ return getLocalTrack(trackId);
476
+ }
477
+
478
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(pcId);
479
+ if (pco == null) {
480
+ Log.d(TAG, "getTrack(): could not find PeerConnection");
481
+ return null;
482
+ }
483
+
484
+ return pco.remoteTracks.get(trackId);
485
+ }
486
+
487
+ MediaStreamTrack getLocalTrack(String trackId) {
488
+ return getUserMediaImpl.getTrack(trackId);
489
+ }
490
+
491
+ public VideoTrack createVideoTrack(AbstractVideoCaptureController videoCaptureController) {
492
+ return getUserMediaImpl.createVideoTrack(videoCaptureController);
493
+ }
494
+
495
+ public void createStream(
496
+ MediaStreamTrack[] tracks, GetUserMediaImpl.BiConsumer<String, ArrayList<WritableMap>> successCallback) {
497
+ getUserMediaImpl.createStream(tracks, successCallback);
498
+ }
499
+
500
+ /**
501
+ * Turns an "options" <tt>ReadableMap</tt> into a <tt>MediaConstraints</tt> object.
502
+ *
503
+ * @param options A <tt>ReadableMap</tt> which represents a JavaScript
504
+ * object specifying the options to be parsed into a
505
+ * <tt>MediaConstraints</tt> instance.
506
+ * @return A new <tt>MediaConstraints</tt> instance initialized with the
507
+ * mandatory keys and values specified by <tt>options</tt>.
508
+ */
509
+ MediaConstraints constraintsForOptions(ReadableMap options) {
510
+ MediaConstraints mediaConstraints = new MediaConstraints();
511
+ ReadableMapKeySetIterator keyIterator = options.keySetIterator();
512
+
513
+ while (keyIterator.hasNextKey()) {
514
+ String key = keyIterator.nextKey();
515
+ String value = ReactBridgeUtil.getMapStrValue(options, key);
516
+
517
+ mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(key, value));
518
+ }
519
+
520
+ return mediaConstraints;
521
+ }
522
+
523
+ @ReactMethod(isBlockingSynchronousMethod = true)
524
+ public WritableMap peerConnectionAddTransceiver(int id, ReadableMap options) {
525
+ try {
526
+ return (WritableMap) ThreadUtils
527
+ .submitToExecutor((Callable<Object>) () -> {
528
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
529
+ if (pco == null) {
530
+ Log.d(TAG, "peerConnectionAddTransceiver() peerConnection is null");
531
+ return null;
532
+ }
533
+
534
+ RtpTransceiver transceiver = null;
535
+ if (options.hasKey("type")) {
536
+ String kind = options.getString("type");
537
+ transceiver = pco.addTransceiver(SerializeUtils.parseMediaType(kind),
538
+ SerializeUtils.parseTransceiverOptions(options.getMap("init")));
539
+ } else if (options.hasKey("trackId")) {
540
+ String trackId = options.getString("trackId");
541
+ MediaStreamTrack track = getLocalTrack(trackId);
542
+ transceiver = pco.addTransceiver(
543
+ track, SerializeUtils.parseTransceiverOptions(options.getMap("init")));
544
+
545
+ } else {
546
+ // This should technically never happen as the JS side checks for that.
547
+ Log.d(TAG, "peerConnectionAddTransceiver() no type nor trackId provided in options");
548
+ return null;
549
+ }
550
+
551
+ if (transceiver == null) {
552
+ Log.d(TAG, "peerConnectionAddTransceiver() Error adding transceiver");
553
+ return null;
554
+ }
555
+ WritableMap params = Arguments.createMap();
556
+ // We need to get a unique order at which the transceiver was created
557
+ // to reorder the cached array of transceivers on the JS layer.
558
+ params.putInt("transceiverOrder", pco.getNextTransceiverId());
559
+ params.putMap("transceiver", SerializeUtils.serializeTransceiver(id, transceiver));
560
+ return params;
561
+ })
562
+ .get();
563
+ } catch (InterruptedException | ExecutionException e) {
564
+ Log.d(TAG, "peerConnectionAddTransceiver() " + e.getMessage());
565
+ return null;
566
+ }
567
+ }
568
+
569
+ @ReactMethod(isBlockingSynchronousMethod = true)
570
+ public WritableMap peerConnectionAddTrack(int id, String trackId, ReadableMap options) {
571
+ try {
572
+ return (WritableMap) ThreadUtils
573
+ .submitToExecutor((Callable<Object>) () -> {
574
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
575
+ if (pco == null) {
576
+ Log.d(TAG, "peerConnectionAddTrack() peerConnection is null");
577
+ return null;
578
+ }
579
+
580
+ MediaStreamTrack track = getLocalTrack(trackId);
581
+ if (track == null) {
582
+ Log.w(TAG, "peerConnectionAddTrack() couldn't find track " + trackId);
583
+ return null;
584
+ }
585
+
586
+ List<String> streamIds = new ArrayList<>();
587
+ if (options.hasKey("streamIds")) {
588
+ ReadableArray rawStreamIds = options.getArray("streamIds");
589
+ if (rawStreamIds != null) {
590
+ for (int i = 0; i < rawStreamIds.size(); i++) {
591
+ streamIds.add(rawStreamIds.getString(i));
592
+ }
593
+ }
594
+ }
595
+ RtpSender sender = pco.getPeerConnection().addTrack(track, streamIds);
596
+
597
+ // Need to get the corresponding transceiver as well
598
+ RtpTransceiver transceiver = pco.getTransceiver(sender.id());
599
+
600
+ // We need the transceiver creation order to reorder the transceivers array
601
+ // in the JS layer.
602
+ WritableMap params = Arguments.createMap();
603
+ params.putInt("transceiverOrder", pco.getNextTransceiverId());
604
+ params.putMap("transceiver", SerializeUtils.serializeTransceiver(id, transceiver));
605
+ params.putMap("sender", SerializeUtils.serializeSender(id, sender));
606
+ return params;
607
+ })
608
+ .get();
609
+ } catch (InterruptedException | ExecutionException e) {
610
+ Log.d(TAG, "peerConnectionAddTrack() " + e.getMessage());
611
+ return null;
612
+ }
613
+ }
614
+
615
+ @ReactMethod(isBlockingSynchronousMethod = true)
616
+ public boolean peerConnectionRemoveTrack(int id, String senderId) {
617
+ try {
618
+ return (boolean) ThreadUtils
619
+ .submitToExecutor((Callable<Object>) () -> {
620
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
621
+ if (pco == null) {
622
+ Log.d(TAG, "peerConnectionRemoveTrack() peerConnection is null");
623
+ return false;
624
+ }
625
+ RtpSender sender = pco.getSender(senderId);
626
+ if (sender == null) {
627
+ Log.w(TAG, "peerConnectionRemoveTrack() sender is null");
628
+ return false;
629
+ }
630
+
631
+ return pco.getPeerConnection().removeTrack(sender);
632
+ })
633
+ .get();
634
+ } catch (InterruptedException | ExecutionException e) {
635
+ Log.d(TAG, "peerConnectionRemoveTrack() " + e.getMessage());
636
+ return false;
637
+ }
638
+ }
639
+
640
+ @ReactMethod
641
+ public void senderSetParameters(int id, String senderId, ReadableMap options, Promise promise) {
642
+ ThreadUtils.runOnExecutor(() -> {
643
+ try {
644
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
645
+ if (pco == null) {
646
+ Log.d(TAG, "senderSetParameters() peerConnectionObserver is null");
647
+ promise.reject(new Exception("Peer Connection is not initialized"));
648
+ return;
649
+ }
650
+
651
+ RtpSender sender = pco.getSender(senderId);
652
+ if (sender == null) {
653
+ Log.w(TAG, "senderSetParameters() sender is null");
654
+ promise.reject(new Exception("Could not get sender"));
655
+ return;
656
+ }
657
+
658
+ RtpParameters params = sender.getParameters();
659
+ params = SerializeUtils.updateRtpParameters(options, params);
660
+ sender.setParameters(params);
661
+ promise.resolve(SerializeUtils.serializeRtpParameters(sender.getParameters()));
662
+ } catch (Exception e) {
663
+ Log.d(TAG, "senderSetParameters: " + e.getMessage());
664
+ promise.reject(e);
665
+ }
666
+ });
667
+ }
668
+
669
+ @ReactMethod
670
+ public void transceiverStop(int id, String senderId, Promise promise) {
671
+ ThreadUtils.runOnExecutor(() -> {
672
+ try {
673
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
674
+ if (pco == null) {
675
+ Log.d(TAG, "transceiverStop() peerConnectionObserver is null");
676
+ promise.reject(new Exception("Peer Connection is not initialized"));
677
+ return;
678
+ }
679
+ RtpTransceiver transceiver = pco.getTransceiver(senderId);
680
+ if (transceiver == null) {
681
+ Log.w(TAG, "transceiverStop() transceiver is null");
682
+ promise.reject(new Exception("Could not get transceiver"));
683
+ return;
684
+ }
685
+
686
+ transceiver.stopStandard();
687
+ promise.resolve(true);
688
+ } catch (Exception e) {
689
+ Log.d(TAG, "transceiverStop(): " + e.getMessage());
690
+ promise.reject(e);
691
+ }
692
+ });
693
+ }
694
+
695
+ @ReactMethod
696
+ public void senderReplaceTrack(int id, String senderId, String trackId, Promise promise) {
697
+ ThreadUtils.runOnExecutor(() -> {
698
+ try {
699
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
700
+ if (pco == null) {
701
+ Log.d(TAG, "senderReplaceTrack() peerConnectionObserver is null");
702
+ promise.reject(new Exception("Peer Connection is not initialized"));
703
+ return;
704
+ }
705
+
706
+ RtpSender sender = pco.getSender(senderId);
707
+ if (sender == null) {
708
+ Log.w(TAG, "senderReplaceTrack() sender is null");
709
+ promise.reject(new Exception("Could not get sender"));
710
+ return;
711
+ }
712
+
713
+ MediaStreamTrack track = getLocalTrack(trackId);
714
+ sender.setTrack(track, false);
715
+ promise.resolve(true);
716
+ } catch (Exception e) {
717
+ Log.d(TAG, "senderReplaceTrack(): " + e.getMessage());
718
+ promise.reject(e);
719
+ }
720
+ });
721
+ }
722
+
723
+ @ReactMethod
724
+ public void transceiverSetDirection(int id, String senderId, String direction, Promise promise) {
725
+ ThreadUtils.runOnExecutor(() -> {
726
+ WritableMap identifier = Arguments.createMap();
727
+ WritableMap params = Arguments.createMap();
728
+ identifier.putInt("peerConnectionId", id);
729
+ identifier.putString("transceiverId", senderId);
730
+ try {
731
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
732
+ if (pco == null) {
733
+ Log.d(TAG, "transceiverSetDirection() peerConnectionObserver is null");
734
+ promise.reject(new Exception("Peer Connection is not initialized"));
735
+ return;
736
+ }
737
+ RtpTransceiver transceiver = pco.getTransceiver(senderId);
738
+ if (transceiver == null) {
739
+ Log.d(TAG, "transceiverSetDirection() transceiver is null");
740
+ promise.reject(new Exception("Could not get sender"));
741
+ return;
742
+ }
743
+
744
+ transceiver.setDirection(SerializeUtils.parseDirection(direction));
745
+
746
+ promise.resolve(true);
747
+ } catch (Exception e) {
748
+ Log.d(TAG, "transceiverSetDirection(): " + e.getMessage());
749
+ promise.reject(e);
750
+ }
751
+ });
752
+ }
753
+
754
+ @ReactMethod(isBlockingSynchronousMethod = true)
755
+ public boolean transceiverSetCodecPreferences(int id, String senderId, ReadableArray codecPreferences) {
756
+ ThreadUtils.runOnExecutor(() -> {
757
+ WritableMap identifier = Arguments.createMap();
758
+ WritableMap params = Arguments.createMap();
759
+ identifier.putInt("peerConnectionId", id);
760
+ identifier.putString("transceiverId", senderId);
761
+ try {
762
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
763
+ if (pco == null) {
764
+ Log.d(TAG, "transceiverSetDirection() peerConnectionObserver is null");
765
+ return;
766
+ }
767
+ RtpTransceiver transceiver = pco.getTransceiver(senderId);
768
+ if (transceiver == null) {
769
+ Log.d(TAG, "transceiverSetDirection() transceiver is null");
770
+ return;
771
+ }
772
+
773
+ // Convert JSON codec capabilities to the actual objects.
774
+ RtpTransceiver.RtpTransceiverDirection direction = transceiver.getDirection();
775
+ List<Pair<Map<String, Object>, RtpCapabilities.CodecCapability>> availableCodecs = new ArrayList<>();
776
+
777
+ if (direction.equals(RtpTransceiver.RtpTransceiverDirection.SEND_RECV)
778
+ || direction.equals(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY)) {
779
+ RtpCapabilities capabilities = mFactory.getRtpSenderCapabilities(transceiver.getMediaType());
780
+ for (RtpCapabilities.CodecCapability codec : capabilities.codecs) {
781
+ Map<String, Object> codecDict = SerializeUtils.serializeRtpCapabilitiesCodec(codec).toHashMap();
782
+ availableCodecs.add(new Pair<>(codecDict, codec));
783
+ }
784
+ }
785
+
786
+ if (direction.equals(RtpTransceiver.RtpTransceiverDirection.SEND_RECV)
787
+ || direction.equals(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY)) {
788
+ RtpCapabilities capabilities = mFactory.getRtpReceiverCapabilities(transceiver.getMediaType());
789
+ for (RtpCapabilities.CodecCapability codec : capabilities.codecs) {
790
+ Map<String, Object> codecDict = SerializeUtils.serializeRtpCapabilitiesCodec(codec).toHashMap();
791
+ availableCodecs.add(new Pair<>(codecDict, codec));
792
+ }
793
+ }
794
+
795
+ // Codec preferences is order sensitive.
796
+ List<RtpCapabilities.CodecCapability> codecsToSet = new ArrayList<>();
797
+
798
+ for (int i = 0; i < codecPreferences.size(); i++) {
799
+ Map<String, Object> codecPref = codecPreferences.getMap(i).toHashMap();
800
+ for (Pair<Map<String, Object>, RtpCapabilities.CodecCapability> pair : availableCodecs) {
801
+ Map<String, Object> availableCodecDict = pair.first;
802
+ if (codecPref.equals(availableCodecDict)) {
803
+ codecsToSet.add(pair.second);
804
+ break;
805
+ }
806
+ }
807
+ }
808
+
809
+ transceiver.setCodecPreferences(codecsToSet);
810
+ } catch (Exception e) {
811
+ Log.d(TAG, "transceiverSetCodecPreferences(): " + e.getMessage());
812
+ }
813
+ });
814
+ return true;
815
+ }
816
+
817
+ @ReactMethod
818
+ public void getDisplayMedia(Promise promise) {
819
+ ThreadUtils.runOnExecutor(() -> getUserMediaImpl.getDisplayMedia(promise));
820
+ }
821
+
822
+ @ReactMethod
823
+ public void getUserMedia(ReadableMap constraints, Callback successCallback, Callback errorCallback) {
824
+ ThreadUtils.runOnExecutor(() -> getUserMediaImpl.getUserMedia(constraints, successCallback, errorCallback));
825
+ }
826
+
827
+ @ReactMethod
828
+ public void enumerateDevices(Callback callback) {
829
+ ThreadUtils.runOnExecutor(() -> callback.invoke(getUserMediaImpl.enumerateDevices()));
830
+ }
831
+
832
+ @ReactMethod
833
+ public void mediaStreamCreate(String id) {
834
+ ThreadUtils.runOnExecutor(() -> {
835
+ MediaStream mediaStream = mFactory.createLocalMediaStream(id);
836
+ localStreams.put(id, mediaStream);
837
+ });
838
+ }
839
+
840
+ @ReactMethod
841
+ public void mediaStreamAddTrack(String streamId, int pcId, String trackId) {
842
+ ThreadUtils.runOnExecutor(() -> {
843
+ MediaStream stream = localStreams.get(streamId);
844
+ if (stream == null) {
845
+ Log.d(TAG, "mediaStreamAddTrack() could not find stream " + streamId);
846
+ return;
847
+ }
848
+
849
+ MediaStreamTrack track = getTrack(pcId, trackId);
850
+ if (track == null) {
851
+ Log.d(TAG, "mediaStreamAddTrack() could not find track " + trackId);
852
+ return;
853
+ }
854
+
855
+ String kind = track.kind();
856
+ if ("audio".equals(kind)) {
857
+ stream.addTrack((AudioTrack) track);
858
+ } else if ("video".equals(kind)) {
859
+ stream.addTrack((VideoTrack) track);
860
+ }
861
+ });
862
+ }
863
+
864
+ @ReactMethod
865
+ public void mediaStreamRemoveTrack(String streamId, int pcId, String trackId) {
866
+ ThreadUtils.runOnExecutor(() -> {
867
+ MediaStream stream = localStreams.get(streamId);
868
+ if (stream == null) {
869
+ Log.d(TAG, "mediaStreamRemoveTrack() could not find stream " + streamId);
870
+ return;
871
+ }
872
+
873
+ MediaStreamTrack track = getTrack(pcId, trackId);
874
+ if (track == null) {
875
+ Log.d(TAG, "mediaStreamRemoveTrack() could not find track " + trackId);
876
+ return;
877
+ }
878
+
879
+ String kind = track.kind();
880
+ if ("audio".equals(kind)) {
881
+ stream.removeTrack((AudioTrack) track);
882
+ } else if ("video".equals(kind)) {
883
+ stream.removeTrack((VideoTrack) track);
884
+ }
885
+ });
886
+ }
887
+
888
+ @ReactMethod
889
+ public void mediaStreamRelease(String id) {
890
+ ThreadUtils.runOnExecutor(() -> {
891
+ MediaStream stream = localStreams.get(id);
892
+ if (stream == null) {
893
+ Log.d(TAG, "mediaStreamRelease() stream is null");
894
+ return;
895
+ }
896
+ localStreams.remove(id);
897
+ stream.dispose();
898
+ });
899
+ }
900
+
901
+ @ReactMethod
902
+ public void mediaStreamTrackRelease(String id) {
903
+ ThreadUtils.runOnExecutor(() -> {
904
+ MediaStreamTrack track = getLocalTrack(id);
905
+ if (track == null) {
906
+ Log.d(TAG, "mediaStreamTrackRelease() track is null");
907
+ return;
908
+ }
909
+ track.setEnabled(false);
910
+ getUserMediaImpl.disposeTrack(id);
911
+ });
912
+ }
913
+
914
+ @ReactMethod
915
+ public void mediaStreamTrackSetEnabled(int pcId, String id, boolean enabled) {
916
+ ThreadUtils.runOnExecutor(() -> {
917
+ MediaStreamTrack track = getTrack(pcId, id);
918
+ if (track == null) {
919
+ Log.d(TAG, "mediaStreamTrackSetEnabled() could not find track " + id);
920
+ return;
921
+ }
922
+
923
+ if (track.enabled() == enabled) {
924
+ return;
925
+ }
926
+ track.setEnabled(enabled);
927
+ getUserMediaImpl.mediaStreamTrackSetEnabled(id, enabled);
928
+ });
929
+ }
930
+
931
+ @ReactMethod
932
+ public void mediaStreamTrackApplyConstraints(String id, ReadableMap constraints, Promise promise) {
933
+ ThreadUtils.runOnExecutor(() -> {
934
+ MediaStreamTrack track = getLocalTrack(id);
935
+ if (track != null) {
936
+ getUserMediaImpl.applyConstraints(id, constraints, promise);
937
+ } else {
938
+ promise.reject(new Exception("mediaStreamTrackApplyConstraints() could not find track " + id));
939
+ }
940
+ });
941
+ }
942
+
943
+ @ReactMethod
944
+ public void mediaStreamTrackSetVolume(int pcId, String id, double volume) {
945
+ ThreadUtils.runOnExecutor(() -> {
946
+ MediaStreamTrack track = getTrack(pcId, id);
947
+ if (track == null) {
948
+ Log.d(TAG, "mediaStreamTrackSetVolume() could not find track " + id);
949
+ return;
950
+ }
951
+
952
+ if (!(track instanceof AudioTrack)) {
953
+ Log.d(TAG, "mediaStreamTrackSetVolume() track is not an AudioTrack!");
954
+ return;
955
+ }
956
+
957
+ ((AudioTrack) track).setVolume(volume);
958
+ });
959
+ }
960
+
961
+ /**
962
+ * This serializes the transceivers current direction and mid and returns them
963
+ * for update when an sdp negotiation/renegotiation happens
964
+ */
965
+ private ReadableArray getTransceiversInfo(PeerConnection peerConnection) {
966
+ WritableArray transceiverUpdates = Arguments.createArray();
967
+
968
+ for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
969
+ WritableMap transceiverUpdate = Arguments.createMap();
970
+
971
+ RtpTransceiver.RtpTransceiverDirection direction = transceiver.getCurrentDirection();
972
+ if (direction != null) {
973
+ String directionSerialized = SerializeUtils.serializeDirection(direction);
974
+ transceiverUpdate.putString("currentDirection", directionSerialized);
975
+ }
976
+
977
+ transceiverUpdate.putString("transceiverId", transceiver.getSender().id());
978
+ transceiverUpdate.putString("mid", transceiver.getMid());
979
+ transceiverUpdate.putBoolean("isStopped", transceiver.isStopped());
980
+ transceiverUpdate.putMap("senderRtpParameters",
981
+ SerializeUtils.serializeRtpParameters(transceiver.getSender().getParameters()));
982
+ transceiverUpdate.putMap("receiverRtpParameters",
983
+ SerializeUtils.serializeRtpParameters(transceiver.getReceiver().getParameters()));
984
+ transceiverUpdates.pushMap(transceiverUpdate);
985
+ }
986
+ return transceiverUpdates;
987
+ }
988
+
989
+ @ReactMethod
990
+ public void mediaStreamTrackSetVideoEffects(String id, ReadableArray names) {
991
+ ThreadUtils.runOnExecutor(() -> { getUserMediaImpl.setVideoEffects(id, names); });
992
+ }
993
+
994
+ @ReactMethod
995
+ public void peerConnectionSetConfiguration(ReadableMap configuration, int id) {
996
+ ThreadUtils.runOnExecutor(() -> {
997
+ PeerConnection peerConnection = getPeerConnection(id);
998
+ if (peerConnection == null) {
999
+ Log.d(TAG, "peerConnectionSetConfiguration() peerConnection is null");
1000
+ return;
1001
+ }
1002
+ peerConnection.setConfiguration(parseRTCConfiguration(configuration));
1003
+ });
1004
+ }
1005
+
1006
+ @ReactMethod
1007
+ public void peerConnectionCreateOffer(int id, ReadableMap options, Promise promise) {
1008
+ ThreadUtils.runOnExecutor(() -> {
1009
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
1010
+ PeerConnection peerConnection = pco.getPeerConnection();
1011
+
1012
+ if (peerConnection == null) {
1013
+ Log.d(TAG, "peerConnectionCreateOffer() peerConnection is null");
1014
+ promise.reject(new Exception("PeerConnection not found"));
1015
+ return;
1016
+ }
1017
+
1018
+ List<String> receiversIds = new ArrayList<>();
1019
+ for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
1020
+ receiversIds.add(transceiver.getReceiver().id());
1021
+ }
1022
+
1023
+ final SdpObserver observer = new SdpObserver() {
1024
+ @Override
1025
+ public void onCreateFailure(String s) {
1026
+ ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1027
+ }
1028
+
1029
+ @Override
1030
+ public void onCreateSuccess(SessionDescription sdp) {
1031
+ ThreadUtils.runOnExecutor(() -> {
1032
+ WritableMap params = Arguments.createMap();
1033
+ WritableMap sdpInfo = Arguments.createMap();
1034
+
1035
+ sdpInfo.putString("sdp", sdp.description);
1036
+ sdpInfo.putString("type", sdp.type.canonicalForm());
1037
+
1038
+ params.putArray("transceiversInfo", getTransceiversInfo(peerConnection));
1039
+ params.putMap("sdpInfo", sdpInfo);
1040
+
1041
+ WritableArray newTransceivers = Arguments.createArray();
1042
+ for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
1043
+ if (!receiversIds.contains(transceiver.getReceiver().id())) {
1044
+ WritableMap newTransceiver = Arguments.createMap();
1045
+ newTransceiver.putInt("transceiverOrder", pco.getNextTransceiverId());
1046
+ newTransceiver.putMap(
1047
+ "transceiver", SerializeUtils.serializeTransceiver(id, transceiver));
1048
+ newTransceivers.pushMap(newTransceiver);
1049
+ }
1050
+ }
1051
+
1052
+ params.putArray("newTransceivers", newTransceivers);
1053
+
1054
+ promise.resolve(params);
1055
+ });
1056
+ }
1057
+
1058
+ @Override
1059
+ public void onSetFailure(String s) {}
1060
+
1061
+ @Override
1062
+ public void onSetSuccess() {}
1063
+ };
1064
+
1065
+ peerConnection.createOffer(observer, constraintsForOptions(options));
1066
+ });
1067
+ }
1068
+
1069
+ @ReactMethod
1070
+ public void peerConnectionCreateAnswer(int id, ReadableMap options, Promise promise) {
1071
+ ThreadUtils.runOnExecutor(() -> {
1072
+ PeerConnection peerConnection = getPeerConnection(id);
1073
+
1074
+ if (peerConnection == null) {
1075
+ Log.d(TAG, "peerConnectionCreateAnswer() peerConnection is null");
1076
+ promise.reject(new Exception("PeerConnection not found"));
1077
+ return;
1078
+ }
1079
+
1080
+ final SdpObserver observer = new SdpObserver() {
1081
+ @Override
1082
+ public void onCreateFailure(String s) {
1083
+ ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1084
+ }
1085
+
1086
+ @Override
1087
+ public void onCreateSuccess(SessionDescription sdp) {
1088
+ ThreadUtils.runOnExecutor(() -> {
1089
+ WritableMap params = Arguments.createMap();
1090
+ WritableMap sdpInfo = Arguments.createMap();
1091
+
1092
+ sdpInfo.putString("sdp", sdp.description);
1093
+ sdpInfo.putString("type", sdp.type.canonicalForm());
1094
+
1095
+ params.putArray("transceiversInfo", getTransceiversInfo(peerConnection));
1096
+ params.putMap("sdpInfo", sdpInfo);
1097
+
1098
+ promise.resolve(params);
1099
+ });
1100
+ }
1101
+
1102
+ @Override
1103
+ public void onSetFailure(String s) {}
1104
+
1105
+ @Override
1106
+ public void onSetSuccess() {}
1107
+ };
1108
+
1109
+ peerConnection.createAnswer(observer, constraintsForOptions(options));
1110
+ });
1111
+ }
1112
+
1113
+ @ReactMethod
1114
+ public void peerConnectionSetLocalDescription(int pcId, ReadableMap desc, Promise promise) {
1115
+ ThreadUtils.runOnExecutor(() -> {
1116
+ PeerConnection peerConnection = getPeerConnection(pcId);
1117
+ if (peerConnection == null) {
1118
+ Log.d(TAG, "peerConnectionSetLocalDescription() peerConnection is null");
1119
+ promise.reject(new Exception("PeerConnection not found"));
1120
+ return;
1121
+ }
1122
+
1123
+ final SdpObserver observer = new SdpObserver() {
1124
+ @Override
1125
+ public void onCreateSuccess(SessionDescription sdp) {}
1126
+
1127
+ @Override
1128
+ public void onSetSuccess() {
1129
+ ThreadUtils.runOnExecutor(() -> {
1130
+ WritableMap newSdpMap = Arguments.createMap();
1131
+ WritableMap params = Arguments.createMap();
1132
+
1133
+ SessionDescription newSdp = peerConnection.getLocalDescription();
1134
+ // Can happen when doing a rollback.
1135
+ if (newSdp != null) {
1136
+ newSdpMap.putString("type", newSdp.type.canonicalForm());
1137
+ newSdpMap.putString("sdp", newSdp.description);
1138
+ }
1139
+
1140
+ params.putMap("sdpInfo", newSdpMap);
1141
+ params.putArray("transceiversInfo", getTransceiversInfo(peerConnection));
1142
+
1143
+ promise.resolve(params);
1144
+ });
1145
+ }
1146
+
1147
+ @Override
1148
+ public void onCreateFailure(String s) {}
1149
+
1150
+ @Override
1151
+ public void onSetFailure(String s) {
1152
+ ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1153
+ }
1154
+ };
1155
+
1156
+ if (desc != null) {
1157
+ SessionDescription sdp = new SessionDescription(
1158
+ SessionDescription.Type.fromCanonicalForm(Objects.requireNonNull(desc.getString("type"))),
1159
+ desc.getString("sdp"));
1160
+
1161
+ peerConnection.setLocalDescription(observer, sdp);
1162
+ } else {
1163
+ peerConnection.setLocalDescription(observer);
1164
+ }
1165
+ });
1166
+ }
1167
+
1168
+ @ReactMethod
1169
+ public void peerConnectionSetRemoteDescription(int id, ReadableMap desc, Promise promise) {
1170
+ ThreadUtils.runOnExecutor(() -> {
1171
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
1172
+ PeerConnection peerConnection = pco.getPeerConnection();
1173
+
1174
+ if (peerConnection == null) {
1175
+ Log.d(TAG, "peerConnectionSetRemoteDescription() peerConnection is null");
1176
+ promise.reject(new Exception("PeerConnection not found"));
1177
+ return;
1178
+ }
1179
+
1180
+ SessionDescription sdp = new SessionDescription(
1181
+ SessionDescription.Type.fromCanonicalForm(desc.getString("type")), desc.getString("sdp"));
1182
+
1183
+ List<String> receiversIds = new ArrayList<>();
1184
+ for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
1185
+ receiversIds.add(transceiver.getReceiver().id());
1186
+ }
1187
+
1188
+ final SdpObserver observer = new SdpObserver() {
1189
+ @Override
1190
+ public void onCreateSuccess(final SessionDescription sdp) {}
1191
+
1192
+ @Override
1193
+ public void onSetSuccess() {
1194
+ ThreadUtils.runOnExecutor(() -> {
1195
+ WritableMap newSdpMap = Arguments.createMap();
1196
+ WritableMap params = Arguments.createMap();
1197
+
1198
+ SessionDescription newSdp = peerConnection.getRemoteDescription();
1199
+ // Be defensive for the rollback cases.
1200
+ if (newSdp != null) {
1201
+ newSdpMap.putString("type", newSdp.type.canonicalForm());
1202
+ newSdpMap.putString("sdp", newSdp.description);
1203
+ }
1204
+
1205
+ params.putArray("transceiversInfo", getTransceiversInfo(peerConnection));
1206
+ params.putMap("sdpInfo", newSdpMap);
1207
+
1208
+ WritableArray newTransceivers = Arguments.createArray();
1209
+ for (RtpTransceiver transceiver : peerConnection.getTransceivers()) {
1210
+ if (!receiversIds.contains(transceiver.getReceiver().id())) {
1211
+ WritableMap newTransceiver = Arguments.createMap();
1212
+ newTransceiver.putInt("transceiverOrder", pco.getNextTransceiverId());
1213
+ newTransceiver.putMap(
1214
+ "transceiver", SerializeUtils.serializeTransceiver(id, transceiver));
1215
+ newTransceivers.pushMap(newTransceiver);
1216
+ }
1217
+ }
1218
+
1219
+ params.putArray("newTransceivers", newTransceivers);
1220
+
1221
+ promise.resolve(params);
1222
+ });
1223
+ }
1224
+
1225
+ @Override
1226
+ public void onCreateFailure(String s) {}
1227
+
1228
+ @Override
1229
+ public void onSetFailure(String s) {
1230
+ ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1231
+ }
1232
+ };
1233
+
1234
+ peerConnection.setRemoteDescription(observer, sdp);
1235
+ });
1236
+ }
1237
+
1238
+ @ReactMethod(isBlockingSynchronousMethod = true)
1239
+ public WritableMap receiverGetCapabilities(String kind) {
1240
+ try {
1241
+ return (WritableMap) ThreadUtils
1242
+ .submitToExecutor((Callable<Object>) () -> {
1243
+ MediaStreamTrack.MediaType mediaType;
1244
+ if (kind.equals("audio")) {
1245
+ mediaType = MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO;
1246
+ } else if (kind.equals("video")) {
1247
+ mediaType = MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO;
1248
+ } else {
1249
+ return Arguments.createMap();
1250
+ }
1251
+
1252
+ RtpCapabilities capabilities = mFactory.getRtpReceiverCapabilities(mediaType);
1253
+ return SerializeUtils.serializeRtpCapabilities(capabilities);
1254
+ })
1255
+ .get();
1256
+ } catch (ExecutionException | InterruptedException e) {
1257
+ Log.d(TAG, "receiverGetCapabilities() " + e.getMessage());
1258
+ return null;
1259
+ }
1260
+ }
1261
+
1262
+ @ReactMethod(isBlockingSynchronousMethod = true)
1263
+ public WritableMap senderGetCapabilities(String kind) {
1264
+ try {
1265
+ return (WritableMap) ThreadUtils
1266
+ .submitToExecutor((Callable<Object>) () -> {
1267
+ MediaStreamTrack.MediaType mediaType;
1268
+ if (kind.equals("audio")) {
1269
+ mediaType = MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO;
1270
+ } else if (kind.equals("video")) {
1271
+ mediaType = MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO;
1272
+ } else {
1273
+ return Arguments.createMap();
1274
+ }
1275
+
1276
+ RtpCapabilities capabilities = mFactory.getRtpSenderCapabilities(mediaType);
1277
+ return SerializeUtils.serializeRtpCapabilities(capabilities);
1278
+ })
1279
+ .get();
1280
+ } catch (ExecutionException | InterruptedException e) {
1281
+ Log.d(TAG, "senderGetCapabilities() " + e.getMessage());
1282
+ return null;
1283
+ }
1284
+ }
1285
+
1286
+ @ReactMethod
1287
+ public void receiverGetStats(int pcId, String receiverId, Promise promise) {
1288
+ ThreadUtils.runOnExecutor(() -> {
1289
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(pcId);
1290
+ if (pco == null || pco.getPeerConnection() == null) {
1291
+ Log.d(TAG, "receiverGetStats() peerConnection is null");
1292
+ promise.resolve(StringUtils.statsToJSON(new RTCStatsReport(0, new HashMap<>())));
1293
+ } else {
1294
+ pco.receiverGetStats(receiverId, promise);
1295
+ }
1296
+ });
1297
+ }
1298
+
1299
+ @ReactMethod
1300
+ public void senderGetStats(int pcId, String senderId, Promise promise) {
1301
+ ThreadUtils.runOnExecutor(() -> {
1302
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(pcId);
1303
+ if (pco == null || pco.getPeerConnection() == null) {
1304
+ Log.d(TAG, "senderGetStats() peerConnection is null");
1305
+ promise.resolve(StringUtils.statsToJSON(new RTCStatsReport(0, new HashMap<>())));
1306
+ } else {
1307
+ pco.senderGetStats(senderId, promise);
1308
+ }
1309
+ });
1310
+ }
1311
+
1312
+ @ReactMethod
1313
+ public void peerConnectionAddICECandidate(int pcId, ReadableMap candidateMap, Promise promise) {
1314
+ ThreadUtils.runOnExecutor(() -> {
1315
+ PeerConnection peerConnection = getPeerConnection(pcId);
1316
+ if (peerConnection == null) {
1317
+ Log.d(TAG, "peerConnectionAddICECandidate() peerConnection is null");
1318
+ promise.reject(new Exception("PeerConnection not found"));
1319
+ return;
1320
+ }
1321
+
1322
+ if (!candidateMap.hasKey("sdpMid") && !candidateMap.hasKey("sdpMLineIndex")) {
1323
+ promise.reject("E_TYPE_ERROR", "Invalid argument");
1324
+ return;
1325
+ }
1326
+
1327
+ IceCandidate candidate = new IceCandidate(candidateMap.hasKey("sdpMid") && !candidateMap.isNull("sdpMid")
1328
+ ? candidateMap.getString("sdpMid")
1329
+ : "",
1330
+ candidateMap.hasKey("sdpMLineIndex") && !candidateMap.isNull("sdpMLineIndex")
1331
+ ? candidateMap.getInt("sdpMLineIndex")
1332
+ : 0,
1333
+ candidateMap.getString("candidate"));
1334
+
1335
+ peerConnection.addIceCandidate(candidate, new AddIceObserver() {
1336
+ @Override
1337
+ public void onAddSuccess() {
1338
+ ThreadUtils.runOnExecutor(() -> {
1339
+ WritableMap newSdpMap = Arguments.createMap();
1340
+ SessionDescription newSdp = peerConnection.getRemoteDescription();
1341
+ newSdpMap.putString("type", newSdp.type.canonicalForm());
1342
+ newSdpMap.putString("sdp", newSdp.description);
1343
+ promise.resolve(newSdpMap);
1344
+ });
1345
+ }
1346
+
1347
+ @Override
1348
+ public void onAddFailure(String s) {
1349
+ ThreadUtils.runOnExecutor(() -> { promise.reject("E_OPERATION_ERROR", s); });
1350
+ }
1351
+ });
1352
+ });
1353
+ }
1354
+
1355
+ @ReactMethod
1356
+ public void peerConnectionGetStats(int peerConnectionId, Promise promise) {
1357
+ ThreadUtils.runOnExecutor(() -> {
1358
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1359
+ if (pco == null || pco.getPeerConnection() == null) {
1360
+ Log.d(TAG, "peerConnectionGetStats() peerConnection is null");
1361
+ promise.resolve(StringUtils.statsToJSON(new RTCStatsReport(0, new HashMap<>())));
1362
+ } else {
1363
+ pco.getStats(promise);
1364
+ }
1365
+ });
1366
+ }
1367
+
1368
+ @ReactMethod
1369
+ public void peerConnectionClose(int id) {
1370
+ ThreadUtils.runOnExecutor(() -> {
1371
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
1372
+ if (pco == null || pco.getPeerConnection() == null) {
1373
+ Log.d(TAG, "peerConnectionClose() peerConnection is null");
1374
+ return;
1375
+ }
1376
+ pco.close();
1377
+ });
1378
+ }
1379
+
1380
+ @ReactMethod
1381
+ public void peerConnectionDispose(int id) {
1382
+ ThreadUtils.runOnExecutor(() -> {
1383
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(id);
1384
+ if (pco == null || pco.getPeerConnection() == null) {
1385
+ Log.d(TAG, "peerConnectionDispose() peerConnection is null");
1386
+ }
1387
+ pco.dispose();
1388
+ mPeerConnectionObservers.remove(id);
1389
+ });
1390
+ }
1391
+
1392
+ @ReactMethod
1393
+ public void peerConnectionRestartIce(int pcId) {
1394
+ ThreadUtils.runOnExecutor(() -> {
1395
+ PeerConnection peerConnection = getPeerConnection(pcId);
1396
+ if (peerConnection == null) {
1397
+ Log.w(TAG, "peerConnectionRestartIce() peerConnection is null");
1398
+ return;
1399
+ }
1400
+
1401
+ peerConnection.restartIce();
1402
+ });
1403
+ }
1404
+
1405
+ @ReactMethod(isBlockingSynchronousMethod = true)
1406
+ public WritableMap createDataChannel(int peerConnectionId, String label, ReadableMap config) {
1407
+ try {
1408
+ return (WritableMap) ThreadUtils
1409
+ .submitToExecutor((Callable<Object>) () -> {
1410
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1411
+ if (pco == null || pco.getPeerConnection() == null) {
1412
+ Log.d(TAG, "createDataChannel() peerConnection is null");
1413
+ return null;
1414
+ } else {
1415
+ return pco.createDataChannel(label, config);
1416
+ }
1417
+ })
1418
+ .get();
1419
+ } catch (ExecutionException | InterruptedException e) {
1420
+ return null;
1421
+ }
1422
+ }
1423
+
1424
+ @ReactMethod
1425
+ public void dataChannelClose(int peerConnectionId, String reactTag) {
1426
+ ThreadUtils.runOnExecutor(() -> {
1427
+ // Forward to PeerConnectionObserver which deals with DataChannels
1428
+ // because DataChannel is owned by PeerConnection.
1429
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1430
+ if (pco == null || pco.getPeerConnection() == null) {
1431
+ Log.d(TAG, "dataChannelClose() peerConnection is null");
1432
+ return;
1433
+ }
1434
+
1435
+ pco.dataChannelClose(reactTag);
1436
+ });
1437
+ }
1438
+
1439
+ @ReactMethod
1440
+ public void dataChannelDispose(int peerConnectionId, String reactTag) {
1441
+ ThreadUtils.runOnExecutor(() -> {
1442
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1443
+ if (pco == null || pco.getPeerConnection() == null) {
1444
+ Log.d(TAG, "dataChannelDispose() peerConnection is null");
1445
+ return;
1446
+ }
1447
+
1448
+ pco.dataChannelDispose(reactTag);
1449
+ });
1450
+ }
1451
+
1452
+ @ReactMethod
1453
+ public void dataChannelSend(int peerConnectionId, String reactTag, String data, String type) {
1454
+ ThreadUtils.runOnExecutor(() -> {
1455
+ // Forward to PeerConnectionObserver which deals with DataChannels
1456
+ // because DataChannel is owned by PeerConnection.
1457
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1458
+ if (pco == null || pco.getPeerConnection() == null) {
1459
+ Log.d(TAG, "dataChannelSend() peerConnection is null");
1460
+ return;
1461
+ }
1462
+
1463
+ pco.dataChannelSend(reactTag, data, type);
1464
+ });
1465
+ }
1466
+
1467
+ // Frame Cryptor methods
1468
+ ////////////////////////////////
1469
+ RTCCryptoManager frameCryptor = new RTCCryptoManager(this);
1470
+
1471
+ @ReactMethod(isBlockingSynchronousMethod = true)
1472
+ public String frameCryptorFactoryCreateFrameCryptor(ReadableMap config) {
1473
+ return frameCryptor.frameCryptorFactoryCreateFrameCryptor(config);
1474
+ }
1475
+
1476
+ @ReactMethod
1477
+ public void frameCryptorSetKeyIndex(ReadableMap config, Promise promise) {
1478
+ frameCryptor.frameCryptorSetKeyIndex(config, promise);
1479
+ }
1480
+
1481
+ @ReactMethod
1482
+ public void frameCryptorGetKeyIndex(ReadableMap config, Promise promise) {
1483
+ frameCryptor.frameCryptorGetKeyIndex(config, promise);
1484
+ }
1485
+
1486
+ @ReactMethod
1487
+ public void frameCryptorSetEnabled(ReadableMap config, Promise promise) {
1488
+ frameCryptor.frameCryptorSetEnabled(config, promise);
1489
+ }
1490
+
1491
+ @ReactMethod
1492
+ public void frameCryptorGetEnabled(ReadableMap config, Promise promise) {
1493
+ frameCryptor.frameCryptorGetEnabled(config, promise);
1494
+ }
1495
+
1496
+ @ReactMethod
1497
+ public void frameCryptorDispose(ReadableMap config, Promise promise) {
1498
+ frameCryptor.frameCryptorDispose(config, promise);
1499
+ }
1500
+
1501
+ @ReactMethod(isBlockingSynchronousMethod = true)
1502
+ public String frameCryptorFactoryCreateKeyProvider(ReadableMap config) {
1503
+ return frameCryptor.frameCryptorFactoryCreateKeyProvider(config);
1504
+ }
1505
+
1506
+ @ReactMethod
1507
+ public void keyProviderSetSharedKey(ReadableMap config, Promise promise) {
1508
+ frameCryptor.keyProviderSetSharedKey(config, promise);
1509
+ }
1510
+
1511
+ @ReactMethod
1512
+ public void keyProviderRatchetSharedKey(ReadableMap config, Promise promise) {
1513
+ frameCryptor.keyProviderRatchetSharedKey(config, promise);
1514
+ }
1515
+
1516
+ @ReactMethod
1517
+ public void keyProviderExportSharedKey(ReadableMap config, Promise promise) {
1518
+ frameCryptor.keyProviderExportSharedKey(config, promise);
1519
+ }
1520
+
1521
+ @ReactMethod
1522
+ public void keyProviderSetKey(ReadableMap config, Promise promise) {
1523
+ frameCryptor.keyProviderSetKey(config, promise);
1524
+ }
1525
+
1526
+ @ReactMethod
1527
+ public void keyProviderRatchetKey(ReadableMap config, Promise promise) {
1528
+ frameCryptor.keyProviderRatchetKey(config, promise);
1529
+ }
1530
+
1531
+ @ReactMethod
1532
+ public void keyProviderExportKey(ReadableMap config, Promise promise) {
1533
+ frameCryptor.keyProviderExportKey(config, promise);
1534
+ }
1535
+
1536
+ @ReactMethod
1537
+ public void keyProviderSetSifTrailer(ReadableMap config, Promise promise) {
1538
+ frameCryptor.keyProviderSetSifTrailer(config, promise);
1539
+ }
1540
+
1541
+ @ReactMethod
1542
+ public void keyProviderDispose(ReadableMap config, Promise promise) {
1543
+ frameCryptor.keyProviderDispose(config, promise);
1544
+ }
1545
+
1546
+ @ReactMethod
1547
+ public void dataPacketCryptorFactoryCreateDataPacketCryptor(ReadableMap params, @NonNull Promise result) {
1548
+ frameCryptor.dataPacketCryptorFactoryCreateDataPacketCryptor(params, result);
1549
+ }
1550
+
1551
+ @ReactMethod
1552
+ public void dataPacketCryptorEncrypt(ReadableMap params, @NonNull Promise result) {
1553
+ frameCryptor.dataPacketCryptorEncrypt(params, result);
1554
+ }
1555
+
1556
+ @ReactMethod
1557
+ public void dataPacketCryptorDecrypt(ReadableMap params, @NonNull Promise result) {
1558
+ frameCryptor.dataPacketCryptorDecrypt(params, result);
1559
+ }
1560
+
1561
+ @ReactMethod
1562
+ public void dataPacketCryptorDispose(ReadableMap params, @NonNull Promise result) {
1563
+ frameCryptor.dataPacketCryptorDispose(params, result);
1564
+ }
1565
+
1566
+ @ReactMethod
1567
+ public void addListener(String eventName) {
1568
+ // Keep: Required for RN built in Event Emitter Calls.
1569
+ }
1570
+
1571
+ @ReactMethod
1572
+ public void removeListeners(Integer count) {
1573
+ // Keep: Required for RN built in Event Emitter Calls.
1574
+ }
1575
+
1576
+ @ReactMethod
1577
+ public void startPalabraTranslation(int peerConnectionId, String trackId, String clientId,
1578
+ String clientSecret, String sourceLang, String targetLang,
1579
+ String apiUrl, Promise promise) {
1580
+ PeerConnectionObserver pco = mPeerConnectionObservers.get(peerConnectionId);
1581
+ if (pco == null) {
1582
+ promise.reject("E_INVALID", "pc_not_found");
1583
+ return;
1584
+ }
1585
+
1586
+ MediaStreamTrack track = pco.remoteTracks.get(trackId);
1587
+ if (track == null) {
1588
+ promise.reject("E_INVALID", "track_not_found");
1589
+ return;
1590
+ }
1591
+
1592
+ if (!(track instanceof AudioTrack)) {
1593
+ promise.reject("E_INVALID", "not_audio_track");
1594
+ return;
1595
+ }
1596
+
1597
+ AudioTrack audioTrack = (AudioTrack) track;
1598
+
1599
+ if (palabraClient != null) {
1600
+ if (palabraClient.matchesSession(trackId, sourceLang, targetLang, apiUrl) && palabraClient.isRunning()) {
1601
+ Log.d(TAG, "palabra_start_reuse");
1602
+ promise.resolve(null);
1603
+ return;
1604
+ }
1605
+ Log.d(TAG, "palabra_start_restart");
1606
+ palabraClient.stop();
1607
+ }
1608
+
1609
+ PalabraConfig config = new PalabraConfig(clientId, clientSecret, sourceLang, targetLang, apiUrl);
1610
+ palabraClient = new PalabraClient(getReactApplicationContext(), config);
1611
+ palabraClient.setListener(new PalabraListener() {
1612
+ @Override
1613
+ public void onTranscription(String text, String lang, boolean isFinal) {
1614
+ WritableMap params = Arguments.createMap();
1615
+ params.putString("text", text);
1616
+ params.putString("lang", lang);
1617
+ params.putBoolean("isFinal", isFinal);
1618
+ sendEvent("palabraTranscription", params);
1619
+ }
1620
+
1621
+ @Override
1622
+ public void onConnectionState(String state) {
1623
+ WritableMap params = Arguments.createMap();
1624
+ params.putString("state", state);
1625
+ sendEvent("palabraConnectionState", params);
1626
+ }
1627
+
1628
+ @Override
1629
+ public void onError(int code, String message) {
1630
+ WritableMap params = Arguments.createMap();
1631
+ params.putInt("code", code);
1632
+ params.putString("message", message);
1633
+ sendEvent("palabraError", params);
1634
+ }
1635
+ });
1636
+
1637
+ palabraClient.start(audioTrack);
1638
+ promise.resolve(null);
1639
+ }
1640
+
1641
+ @ReactMethod
1642
+ public void stopPalabraTranslation(Promise promise) {
1643
+ if (palabraClient != null) {
1644
+ palabraClient.stop();
1645
+ palabraClient = null;
1646
+ }
1647
+ promise.resolve(null);
1648
+ }
1649
+ }