@sbhjt-gr/react-native-webrtc 124.0.0 → 124.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) 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 +1643 -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 +464 -464
  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 +36 -36
  62. package/ios/RCTWebRTC/PalabraClient.m +584 -584
  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/WebRTCModule+Palabra.h +4 -4
  86. package/ios/RCTWebRTC/WebRTCModule+Palabra.m +83 -83
  87. package/ios/RCTWebRTC/WebRTCModule+Permissions.m +75 -75
  88. package/ios/RCTWebRTC/WebRTCModule+RTCAudioSession.m +20 -20
  89. package/ios/RCTWebRTC/WebRTCModule+RTCDataChannel.h +14 -14
  90. package/ios/RCTWebRTC/WebRTCModule+RTCDataChannel.m +165 -165
  91. package/ios/RCTWebRTC/WebRTCModule+RTCFrameCryptor.m +611 -611
  92. package/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.h +13 -13
  93. package/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m +728 -533
  94. package/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.h +24 -24
  95. package/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m +1004 -1004
  96. package/ios/RCTWebRTC/WebRTCModule+Transceivers.m +267 -267
  97. package/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h +12 -12
  98. package/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m +166 -166
  99. package/ios/RCTWebRTC/WebRTCModule.h +58 -51
  100. package/ios/RCTWebRTC/WebRTCModule.m +169 -151
  101. package/ios/RCTWebRTC/WebRTCModuleOptions.h +24 -24
  102. package/ios/RCTWebRTC/WebRTCModuleOptions.m +31 -31
  103. package/ios/RCTWebRTC/videoEffects/ProcessorProvider.h +9 -9
  104. package/ios/RCTWebRTC/videoEffects/ProcessorProvider.m +23 -23
  105. package/ios/RCTWebRTC/videoEffects/VideoEffectProcessor.h +13 -13
  106. package/ios/RCTWebRTC/videoEffects/VideoEffectProcessor.m +23 -23
  107. package/ios/RCTWebRTC/videoEffects/VideoFrameProcessor.h +8 -8
  108. package/ios/RCTWebRTC.xcodeproj/project.pbxproj +404 -404
  109. package/ios/RCTWebRTC.xcworkspace/contents.xcworkspacedata +10 -10
  110. package/lib/commonjs/Constraints.js.map +1 -1
  111. package/lib/commonjs/EventEmitter.js.map +1 -1
  112. package/lib/commonjs/Logger.js.map +1 -1
  113. package/lib/commonjs/MediaDevices.js +17 -17
  114. package/lib/commonjs/MediaDevices.js.map +1 -1
  115. package/lib/commonjs/MediaStream.js +19 -19
  116. package/lib/commonjs/MediaStream.js.map +1 -1
  117. package/lib/commonjs/MediaStreamError.js.map +1 -1
  118. package/lib/commonjs/MediaStreamErrorEvent.js.map +1 -1
  119. package/lib/commonjs/MediaStreamTrack.js +28 -28
  120. package/lib/commonjs/MediaStreamTrack.js.map +1 -1
  121. package/lib/commonjs/MediaStreamTrackEvent.js +6 -6
  122. package/lib/commonjs/MediaStreamTrackEvent.js.map +1 -1
  123. package/lib/commonjs/MessageEvent.js +7 -7
  124. package/lib/commonjs/MessageEvent.js.map +1 -1
  125. package/lib/commonjs/Permissions.js +28 -28
  126. package/lib/commonjs/Permissions.js.map +1 -1
  127. package/lib/commonjs/RTCAudioSession.js +4 -4
  128. package/lib/commonjs/RTCAudioSession.js.map +1 -1
  129. package/lib/commonjs/RTCDataChannel.js +2 -2
  130. package/lib/commonjs/RTCDataChannel.js.map +1 -1
  131. package/lib/commonjs/RTCDataChannelEvent.js +6 -6
  132. package/lib/commonjs/RTCDataChannelEvent.js.map +1 -1
  133. package/lib/commonjs/RTCDataPacketCryptor.js.map +1 -1
  134. package/lib/commonjs/RTCDataPacketCryptorFactory.js.map +1 -1
  135. package/lib/commonjs/RTCErrorEvent.js +3 -3
  136. package/lib/commonjs/RTCErrorEvent.js.map +1 -1
  137. package/lib/commonjs/RTCFrameCryptor.js +8 -8
  138. package/lib/commonjs/RTCFrameCryptor.js.map +1 -1
  139. package/lib/commonjs/RTCFrameCryptorFactory.js.map +1 -1
  140. package/lib/commonjs/RTCIceCandidate.js.map +1 -1
  141. package/lib/commonjs/RTCIceCandidateEvent.js +7 -7
  142. package/lib/commonjs/RTCIceCandidateEvent.js.map +1 -1
  143. package/lib/commonjs/RTCKeyProvider.js.map +1 -1
  144. package/lib/commonjs/RTCPIPView.js +2 -2
  145. package/lib/commonjs/RTCPIPView.js.map +1 -1
  146. package/lib/commonjs/RTCPIPView.web.js.map +1 -1
  147. package/lib/commonjs/RTCPeerConnection.js +36 -36
  148. package/lib/commonjs/RTCPeerConnection.js.map +1 -1
  149. package/lib/commonjs/RTCRtcpParameters.js.map +1 -1
  150. package/lib/commonjs/RTCRtpCapabilities.js +2 -2
  151. package/lib/commonjs/RTCRtpCapabilities.js.map +1 -1
  152. package/lib/commonjs/RTCRtpCodecCapability.js.map +1 -1
  153. package/lib/commonjs/RTCRtpCodecParameters.js.map +1 -1
  154. package/lib/commonjs/RTCRtpEncodingParameters.js.map +1 -1
  155. package/lib/commonjs/RTCRtpHeaderExtension.js.map +1 -1
  156. package/lib/commonjs/RTCRtpParameters.js.map +1 -1
  157. package/lib/commonjs/RTCRtpReceiveParameters.js.map +1 -1
  158. package/lib/commonjs/RTCRtpReceiver.js +7 -7
  159. package/lib/commonjs/RTCRtpReceiver.js.map +1 -1
  160. package/lib/commonjs/RTCRtpSendParameters.js +3 -3
  161. package/lib/commonjs/RTCRtpSendParameters.js.map +1 -1
  162. package/lib/commonjs/RTCRtpSender.js +7 -7
  163. package/lib/commonjs/RTCRtpSender.js.map +1 -1
  164. package/lib/commonjs/RTCRtpTransceiver.js.map +1 -1
  165. package/lib/commonjs/RTCSessionDescription.js.map +1 -1
  166. package/lib/commonjs/RTCTrackEvent.js +6 -6
  167. package/lib/commonjs/RTCTrackEvent.js.map +1 -1
  168. package/lib/commonjs/RTCUtil.js +28 -28
  169. package/lib/commonjs/RTCUtil.js.map +1 -1
  170. package/lib/commonjs/RTCView.js +5 -5
  171. package/lib/commonjs/RTCView.js.map +1 -1
  172. package/lib/commonjs/RTCView.web.js.map +1 -1
  173. package/lib/commonjs/ScreenCapturePickerView.js.map +1 -1
  174. package/lib/commonjs/ScreenCapturePickerView.web.js.map +1 -1
  175. package/lib/commonjs/getDisplayMedia.js.map +1 -1
  176. package/lib/commonjs/getUserMedia.js.map +1 -1
  177. package/lib/commonjs/index.js.map +1 -1
  178. package/lib/commonjs/index.web.js.map +1 -1
  179. package/lib/commonjs/webStream.js.map +1 -1
  180. package/lib/module/Constraints.js.map +1 -1
  181. package/lib/module/EventEmitter.js.map +1 -1
  182. package/lib/module/Logger.js.map +1 -1
  183. package/lib/module/MediaDevices.js +17 -17
  184. package/lib/module/MediaDevices.js.map +1 -1
  185. package/lib/module/MediaStream.js +19 -19
  186. package/lib/module/MediaStream.js.map +1 -1
  187. package/lib/module/MediaStreamError.js.map +1 -1
  188. package/lib/module/MediaStreamErrorEvent.js.map +1 -1
  189. package/lib/module/MediaStreamTrack.js +28 -28
  190. package/lib/module/MediaStreamTrack.js.map +1 -1
  191. package/lib/module/MediaStreamTrackEvent.js +6 -6
  192. package/lib/module/MediaStreamTrackEvent.js.map +1 -1
  193. package/lib/module/MessageEvent.js +7 -7
  194. package/lib/module/MessageEvent.js.map +1 -1
  195. package/lib/module/Permissions.js +28 -28
  196. package/lib/module/Permissions.js.map +1 -1
  197. package/lib/module/RTCAudioSession.js +4 -4
  198. package/lib/module/RTCAudioSession.js.map +1 -1
  199. package/lib/module/RTCDataChannel.js +2 -2
  200. package/lib/module/RTCDataChannel.js.map +1 -1
  201. package/lib/module/RTCDataChannelEvent.js +6 -6
  202. package/lib/module/RTCDataChannelEvent.js.map +1 -1
  203. package/lib/module/RTCDataPacketCryptor.js.map +1 -1
  204. package/lib/module/RTCDataPacketCryptorFactory.js.map +1 -1
  205. package/lib/module/RTCErrorEvent.js +3 -3
  206. package/lib/module/RTCErrorEvent.js.map +1 -1
  207. package/lib/module/RTCFrameCryptor.js +8 -8
  208. package/lib/module/RTCFrameCryptor.js.map +1 -1
  209. package/lib/module/RTCFrameCryptorFactory.js.map +1 -1
  210. package/lib/module/RTCIceCandidate.js.map +1 -1
  211. package/lib/module/RTCIceCandidateEvent.js +7 -7
  212. package/lib/module/RTCIceCandidateEvent.js.map +1 -1
  213. package/lib/module/RTCKeyProvider.js.map +1 -1
  214. package/lib/module/RTCPIPView.js +2 -2
  215. package/lib/module/RTCPIPView.js.map +1 -1
  216. package/lib/module/RTCPIPView.web.js.map +1 -1
  217. package/lib/module/RTCPeerConnection.js +36 -36
  218. package/lib/module/RTCPeerConnection.js.map +1 -1
  219. package/lib/module/RTCRtcpParameters.js.map +1 -1
  220. package/lib/module/RTCRtpCapabilities.js +2 -2
  221. package/lib/module/RTCRtpCapabilities.js.map +1 -1
  222. package/lib/module/RTCRtpCodecCapability.js.map +1 -1
  223. package/lib/module/RTCRtpCodecParameters.js.map +1 -1
  224. package/lib/module/RTCRtpEncodingParameters.js.map +1 -1
  225. package/lib/module/RTCRtpHeaderExtension.js.map +1 -1
  226. package/lib/module/RTCRtpParameters.js.map +1 -1
  227. package/lib/module/RTCRtpReceiveParameters.js.map +1 -1
  228. package/lib/module/RTCRtpReceiver.js +7 -7
  229. package/lib/module/RTCRtpReceiver.js.map +1 -1
  230. package/lib/module/RTCRtpSendParameters.js +3 -3
  231. package/lib/module/RTCRtpSendParameters.js.map +1 -1
  232. package/lib/module/RTCRtpSender.js +7 -7
  233. package/lib/module/RTCRtpSender.js.map +1 -1
  234. package/lib/module/RTCRtpTransceiver.js.map +1 -1
  235. package/lib/module/RTCSessionDescription.js.map +1 -1
  236. package/lib/module/RTCTrackEvent.js +6 -6
  237. package/lib/module/RTCTrackEvent.js.map +1 -1
  238. package/lib/module/RTCUtil.js +28 -28
  239. package/lib/module/RTCUtil.js.map +1 -1
  240. package/lib/module/RTCView.js +5 -5
  241. package/lib/module/RTCView.js.map +1 -1
  242. package/lib/module/RTCView.web.js.map +1 -1
  243. package/lib/module/ScreenCapturePickerView.js.map +1 -1
  244. package/lib/module/ScreenCapturePickerView.web.js.map +1 -1
  245. package/lib/module/getDisplayMedia.js.map +1 -1
  246. package/lib/module/getUserMedia.js.map +1 -1
  247. package/lib/module/index.js.map +1 -1
  248. package/lib/module/index.web.js.map +1 -1
  249. package/lib/module/webStream.js.map +1 -1
  250. package/lib/typescript/Constraints.d.ts +19 -19
  251. package/lib/typescript/EventEmitter.d.ts +6 -6
  252. package/lib/typescript/Logger.d.ts +13 -13
  253. package/lib/typescript/MediaDevices.d.ts +30 -30
  254. package/lib/typescript/MediaStream.d.ts +48 -48
  255. package/lib/typescript/MediaStreamError.d.ts +6 -6
  256. package/lib/typescript/MediaStreamErrorEvent.d.ts +6 -6
  257. package/lib/typescript/MediaStreamTrack.d.ts +101 -101
  258. package/lib/typescript/MediaStreamTrackEvent.d.ts +19 -19
  259. package/lib/typescript/MessageEvent.d.ts +20 -20
  260. package/lib/typescript/Permissions.d.ts +55 -55
  261. package/lib/typescript/RTCAudioSession.d.ts +10 -10
  262. package/lib/typescript/RTCDataChannel.d.ts +43 -43
  263. package/lib/typescript/RTCDataChannelEvent.d.ts +19 -19
  264. package/lib/typescript/RTCDataPacketCryptor.d.ts +12 -12
  265. package/lib/typescript/RTCDataPacketCryptorFactory.d.ts +6 -6
  266. package/lib/typescript/RTCErrorEvent.d.ts +12 -12
  267. package/lib/typescript/RTCFrameCryptor.d.ts +47 -47
  268. package/lib/typescript/RTCFrameCryptorFactory.d.ts +21 -21
  269. package/lib/typescript/RTCIceCandidate.d.ts +17 -17
  270. package/lib/typescript/RTCIceCandidateEvent.d.ts +20 -20
  271. package/lib/typescript/RTCKeyProvider.d.ts +21 -21
  272. package/lib/typescript/RTCPIPView.d.ts +15 -15
  273. package/lib/typescript/RTCPIPView.web.d.ts +13 -13
  274. package/lib/typescript/RTCPeerConnection.d.ts +117 -117
  275. package/lib/typescript/RTCRtcpParameters.d.ts +10 -10
  276. package/lib/typescript/RTCRtpCapabilities.d.ts +9 -9
  277. package/lib/typescript/RTCRtpCodecCapability.d.ts +7 -7
  278. package/lib/typescript/RTCRtpCodecParameters.d.ts +16 -16
  279. package/lib/typescript/RTCRtpEncodingParameters.d.ts +23 -23
  280. package/lib/typescript/RTCRtpHeaderExtension.d.ts +12 -12
  281. package/lib/typescript/RTCRtpParameters.d.ts +19 -19
  282. package/lib/typescript/RTCRtpReceiveParameters.d.ts +4 -4
  283. package/lib/typescript/RTCRtpReceiver.d.ts +21 -21
  284. package/lib/typescript/RTCRtpSendParameters.d.ts +20 -20
  285. package/lib/typescript/RTCRtpSender.d.ts +22 -22
  286. package/lib/typescript/RTCRtpTransceiver.d.ts +31 -31
  287. package/lib/typescript/RTCSessionDescription.d.ts +12 -12
  288. package/lib/typescript/RTCTrackEvent.d.ts +29 -29
  289. package/lib/typescript/RTCUtil.d.ts +37 -37
  290. package/lib/typescript/RTCView.d.ts +117 -117
  291. package/lib/typescript/RTCView.web.d.ts +25 -25
  292. package/lib/typescript/ScreenCapturePickerView.d.ts +2 -2
  293. package/lib/typescript/ScreenCapturePickerView.web.d.ts +1 -1
  294. package/lib/typescript/getDisplayMedia.d.ts +2 -2
  295. package/lib/typescript/getUserMedia.d.ts +7 -7
  296. package/lib/typescript/index.d.ts +22 -22
  297. package/lib/typescript/index.web.d.ts +101 -101
  298. package/lib/typescript/webStream.d.ts +3 -3
  299. package/livekit-react-native-webrtc.podspec +29 -29
  300. package/macos/RCTWebRTC.xcodeproj/project.pbxproj +324 -324
  301. package/macos/RCTWebRTC.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -7
  302. package/macos/RCTWebRTC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -8
  303. package/metro.config.js +7 -7
  304. package/metro.config.macos.js +14 -14
  305. package/package.json +66 -66
  306. package/react-native.config.js +11 -11
  307. package/src/.eslintrc.cjs +67 -67
  308. package/src/Constraints.ts +20 -20
  309. package/src/EventEmitter.ts +65 -65
  310. package/src/Logger.ts +49 -49
  311. package/src/MediaDevices.ts +53 -53
  312. package/src/MediaStream.ts +161 -161
  313. package/src/MediaStreamError.ts +12 -12
  314. package/src/MediaStreamErrorEvent.ts +11 -11
  315. package/src/MediaStreamTrack.ts +282 -282
  316. package/src/MediaStreamTrackEvent.ts +25 -25
  317. package/src/MessageEvent.ts +26 -26
  318. package/src/Permissions.ts +133 -133
  319. package/src/RTCAudioSession.ts +25 -25
  320. package/src/RTCDataChannel.ts +190 -190
  321. package/src/RTCDataChannelEvent.ts +28 -28
  322. package/src/RTCDataPacketCryptor.ts +90 -90
  323. package/src/RTCDataPacketCryptorFactory.ts +24 -24
  324. package/src/RTCErrorEvent.ts +20 -20
  325. package/src/RTCFrameCryptor.ts +162 -162
  326. package/src/RTCFrameCryptorFactory.ts +101 -101
  327. package/src/RTCIceCandidate.ts +29 -29
  328. package/src/RTCIceCandidateEvent.ts +26 -26
  329. package/src/RTCKeyProvider.ts +117 -117
  330. package/src/RTCPIPView.tsx +46 -46
  331. package/src/RTCPIPView.web.tsx +18 -18
  332. package/src/RTCPeerConnection.ts +832 -832
  333. package/src/RTCRtcpParameters.ts +23 -23
  334. package/src/RTCRtpCapabilities.ts +16 -16
  335. package/src/RTCRtpCodecCapability.ts +12 -12
  336. package/src/RTCRtpCodecParameters.ts +44 -44
  337. package/src/RTCRtpEncodingParameters.ts +90 -90
  338. package/src/RTCRtpHeaderExtension.ts +27 -27
  339. package/src/RTCRtpParameters.ts +37 -37
  340. package/src/RTCRtpReceiveParameters.ts +7 -7
  341. package/src/RTCRtpReceiver.ts +60 -60
  342. package/src/RTCRtpSendParameters.ts +63 -63
  343. package/src/RTCRtpSender.ts +78 -78
  344. package/src/RTCRtpTransceiver.ts +107 -107
  345. package/src/RTCSessionDescription.ts +30 -30
  346. package/src/RTCTrackEvent.ts +42 -42
  347. package/src/RTCUtil.ts +211 -211
  348. package/src/RTCView.ts +122 -122
  349. package/src/RTCView.web.tsx +80 -80
  350. package/src/ScreenCapturePickerView.ts +4 -4
  351. package/src/ScreenCapturePickerView.web.tsx +3 -3
  352. package/src/getDisplayMedia.ts +30 -30
  353. package/src/getUserMedia.ts +111 -111
  354. package/src/index.ts +107 -107
  355. package/src/index.web.ts +191 -191
  356. package/src/webStream.ts +31 -31
  357. package/tools/format.sh +6 -6
  358. package/tools/release.sh +45 -45
  359. package/tsconfig.json +17 -17
  360. package/.claude/settings.local.json +0 -9
@@ -1,832 +1,832 @@
1
- import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';
2
- import { NativeModules } from 'react-native';
3
-
4
- import { addListener, removeListener } from './EventEmitter';
5
- import Logger from './Logger';
6
- import MediaStream from './MediaStream';
7
- import MediaStreamTrack from './MediaStreamTrack';
8
- import MediaStreamTrackEvent from './MediaStreamTrackEvent';
9
- import RTCDataChannel from './RTCDataChannel';
10
- import RTCDataChannelEvent from './RTCDataChannelEvent';
11
- import RTCIceCandidate from './RTCIceCandidate';
12
- import RTCIceCandidateEvent from './RTCIceCandidateEvent';
13
- import RTCRtpReceiveParameters from './RTCRtpReceiveParameters';
14
- import RTCRtpReceiver from './RTCRtpReceiver';
15
- import RTCRtpSendParameters from './RTCRtpSendParameters';
16
- import RTCRtpSender from './RTCRtpSender';
17
- import RTCRtpTransceiver from './RTCRtpTransceiver';
18
- import RTCSessionDescription, { RTCSessionDescriptionInit } from './RTCSessionDescription';
19
- import RTCTrackEvent from './RTCTrackEvent';
20
- import * as RTCUtil from './RTCUtil';
21
- import { RTCOfferOptions } from './RTCUtil';
22
-
23
- const log = new Logger('pc');
24
- const { WebRTCModule } = NativeModules;
25
-
26
- type RTCSignalingState =
27
- | 'stable'
28
- | 'have-local-offer'
29
- | 'have-remote-offer'
30
- | 'have-local-pranswer'
31
- | 'have-remote-pranswer'
32
- | 'closed';
33
-
34
- type RTCIceGatheringState = 'new' | 'gathering' | 'complete';
35
-
36
- type RTCPeerConnectionState = 'new' | 'connecting' | 'connected' | 'disconnected' | 'failed' | 'closed';
37
-
38
- type RTCIceConnectionState = 'new' | 'checking' | 'connected' | 'completed' | 'failed' | 'disconnected' | 'closed';
39
-
40
- type RTCDataChannelInit = {
41
- ordered?: boolean,
42
- maxPacketLifeTime?: number,
43
- maxRetransmits?: number,
44
- protocol?: string,
45
- negotiated?: boolean,
46
- id?: number
47
- };
48
-
49
- type RTCIceServer = {
50
- credential?: string,
51
- url?: string, // Deprecated.
52
- urls?: string | string[],
53
- username?: string
54
- };
55
-
56
- type RTCConfiguration = {
57
- bundlePolicy?: 'balanced' | 'max-compat' | 'max-bundle',
58
- iceCandidatePoolSize?: number,
59
- iceServers?: RTCIceServer[],
60
- iceTransportPolicy?: 'all' | 'relay',
61
- rtcpMuxPolicy?: 'negotiate' | 'require'
62
- };
63
-
64
- type RTCPeerConnectionEventMap = {
65
- connectionstatechange: Event<'connectionstatechange'>
66
- icecandidate: RTCIceCandidateEvent<'icecandidate'>
67
- icecandidateerror: RTCIceCandidateEvent<'icecandidateerror'>
68
- iceconnectionstatechange: Event<'iceconnectionstatechange'>
69
- icegatheringstatechange: Event<'icegatheringstatechange'>
70
- negotiationneeded: Event<'negotiationneeded'>
71
- signalingstatechange: Event<'signalingstatechange'>
72
- datachannel: RTCDataChannelEvent<'datachannel'>
73
- track: RTCTrackEvent<'track'>
74
- error: Event<'error'>
75
- }
76
-
77
- let nextPeerConnectionId = 0;
78
-
79
- export default class RTCPeerConnection extends EventTarget<RTCPeerConnectionEventMap> {
80
- localDescription: RTCSessionDescription | null = null;
81
- remoteDescription: RTCSessionDescription | null = null;
82
- signalingState: RTCSignalingState = 'stable';
83
- iceGatheringState: RTCIceGatheringState = 'new';
84
- connectionState: RTCPeerConnectionState = 'new';
85
- iceConnectionState: RTCIceConnectionState = 'new';
86
-
87
- _pcId: number;
88
- _transceivers: { order: number, transceiver: RTCRtpTransceiver }[];
89
- _remoteStreams: Map<string, MediaStream>;
90
- _pendingTrackEvents: any[];
91
-
92
- constructor(configuration?: RTCConfiguration) {
93
- super();
94
-
95
- this._pcId = nextPeerConnectionId++;
96
-
97
- // Sanitize ICE servers.
98
- if (configuration) {
99
- const servers = configuration?.iceServers ?? [];
100
-
101
- for (const server of servers) {
102
- let urls = server.url || server.urls;
103
-
104
- delete server.url;
105
- delete server.urls;
106
-
107
- if (!urls) {
108
- continue;
109
- }
110
-
111
- if (!Array.isArray(urls)) {
112
- urls = [ urls ];
113
- }
114
-
115
- // Native WebRTC does case sensitive parsing.
116
- server.urls = urls.map(url => url.toLowerCase());
117
- }
118
-
119
- // Filter out bogus servers.
120
- configuration.iceServers = servers.filter(s => s.urls);
121
- }
122
-
123
- if (!WebRTCModule.peerConnectionInit(configuration, this._pcId)) {
124
- throw new Error('Failed to initialize PeerConnection, check the native logs!');
125
- }
126
-
127
- this._transceivers = [];
128
- this._remoteStreams = new Map();
129
- this._pendingTrackEvents = [];
130
-
131
- this._registerEvents();
132
-
133
- log.debug(`${this._pcId} ctor`);
134
- }
135
-
136
- async createOffer(options?:RTCOfferOptions) {
137
- log.debug(`${this._pcId} createOffer`);
138
-
139
- const {
140
- sdpInfo,
141
- newTransceivers,
142
- transceiversInfo
143
- } = await WebRTCModule.peerConnectionCreateOffer(this._pcId, RTCUtil.normalizeOfferOptions(options));
144
-
145
- log.debug(`${this._pcId} createOffer OK`);
146
-
147
- newTransceivers?.forEach(t => {
148
- const { transceiverOrder, transceiver } = t;
149
- const newSender = new RTCRtpSender({ ...transceiver.sender, track: null });
150
- const remoteTrack
151
- = transceiver.receiver.track ? new MediaStreamTrack(transceiver.receiver.track) : null;
152
- const newReceiver = new RTCRtpReceiver({ ...transceiver.receiver, track: remoteTrack });
153
- const newTransceiver = new RTCRtpTransceiver({
154
- ...transceiver,
155
- sender: newSender,
156
- receiver: newReceiver,
157
- });
158
-
159
- this._insertTransceiverSorted(transceiverOrder, newTransceiver);
160
- });
161
-
162
- this._updateTransceivers(transceiversInfo);
163
-
164
- return sdpInfo;
165
- }
166
-
167
- async createAnswer() {
168
- log.debug(`${this._pcId} createAnswer`);
169
-
170
- const {
171
- sdpInfo,
172
- transceiversInfo
173
- } = await WebRTCModule.peerConnectionCreateAnswer(this._pcId, {});
174
-
175
- this._updateTransceivers(transceiversInfo);
176
-
177
- return sdpInfo;
178
- }
179
-
180
- setConfiguration(configuration): void {
181
- WebRTCModule.peerConnectionSetConfiguration(configuration, this._pcId);
182
- }
183
-
184
- async setLocalDescription(sessionDescription?: RTCSessionDescription | RTCSessionDescriptionInit): Promise<void> {
185
- log.debug(`${this._pcId} setLocalDescription`);
186
-
187
- let desc;
188
-
189
- if (sessionDescription) {
190
- desc = {
191
- type: sessionDescription.type,
192
- sdp: sessionDescription.sdp ?? ''
193
- };
194
-
195
- if (!RTCUtil.isSdpTypeValid(desc.type)) {
196
- throw new Error(`Invalid session description: invalid type: ${desc.type}`);
197
- }
198
- } else {
199
- desc = null;
200
- }
201
-
202
- const {
203
- sdpInfo,
204
- transceiversInfo
205
- } = await WebRTCModule.peerConnectionSetLocalDescription(this._pcId, desc);
206
-
207
- if (sdpInfo.type && sdpInfo.sdp) {
208
- this.localDescription = new RTCSessionDescription(sdpInfo);
209
- } else {
210
- this.localDescription = null;
211
- }
212
-
213
- this._updateTransceivers(transceiversInfo, /* removeStopped */ desc?.type === 'answer');
214
-
215
- log.debug(`${this._pcId} setLocalDescription OK`);
216
- }
217
-
218
- async setRemoteDescription(sessionDescription: RTCSessionDescription | RTCSessionDescriptionInit): Promise<void> {
219
- log.debug(`${this._pcId} setRemoteDescription`);
220
-
221
- if (!sessionDescription) {
222
- return Promise.reject(new Error('No session description provided'));
223
- }
224
-
225
- const desc = {
226
- type: sessionDescription.type,
227
- sdp: sessionDescription.sdp ?? ''
228
- };
229
-
230
- if (!RTCUtil.isSdpTypeValid(desc.type ?? '')) {
231
- throw new Error(`Invalid session description: invalid type: ${desc.type}`);
232
- }
233
-
234
- const {
235
- sdpInfo,
236
- newTransceivers,
237
- transceiversInfo
238
- } = await WebRTCModule.peerConnectionSetRemoteDescription(this._pcId, desc);
239
-
240
- if (sdpInfo.type && sdpInfo.sdp) {
241
- this.remoteDescription = new RTCSessionDescription(sdpInfo);
242
- } else {
243
- this.remoteDescription = null;
244
- }
245
-
246
- newTransceivers?.forEach(t => {
247
- const { transceiverOrder, transceiver } = t;
248
- const newSender = new RTCRtpSender({ ...transceiver.sender, track: null });
249
- const remoteTrack
250
- = transceiver.receiver.track ? new MediaStreamTrack(transceiver.receiver.track) : null;
251
- const newReceiver = new RTCRtpReceiver({ ...transceiver.receiver, track: remoteTrack });
252
- const newTransceiver = new RTCRtpTransceiver({
253
- ...transceiver,
254
- sender: newSender,
255
- receiver: newReceiver,
256
- });
257
-
258
- this._insertTransceiverSorted(transceiverOrder, newTransceiver);
259
- });
260
-
261
- this._updateTransceivers(transceiversInfo, /* removeStopped */ desc.type === 'answer');
262
-
263
- // Fire track events. They must fire before sRD resolves.
264
- const pendingTrackEvents = this._pendingTrackEvents;
265
-
266
- this._pendingTrackEvents = [];
267
-
268
- for (const ev of pendingTrackEvents) {
269
- const [ transceiver ] = this
270
- .getTransceivers()
271
- .filter(t => t.receiver.id === ev.receiver.id);
272
-
273
- // We need to fire this event for an existing track sometimes, like
274
- // when the transceiver direction (on the sending side) switches from
275
- // sendrecv to recvonly and then back.
276
-
277
- // @ts-ignore
278
- const track: MediaStreamTrack = transceiver.receiver.track;
279
-
280
- transceiver._mid = ev.transceiver.mid;
281
- transceiver._currentDirection = ev.transceiver.currentDirection;
282
- transceiver._direction = ev.transceiver.direction;
283
-
284
- // Get the stream object from the event. Create if necessary.
285
- const streams: MediaStream[] = ev.streams.map(streamInfo => {
286
- // Here we are making sure that we don't create stream objects that already exist
287
- // So that event listeners do get the same object if it has been created before.
288
- if (!this._remoteStreams.has(streamInfo.streamId)) {
289
- const stream = new MediaStream({
290
- streamId: streamInfo.streamId,
291
- streamReactTag: streamInfo.streamReactTag,
292
- tracks: []
293
- });
294
-
295
- this._remoteStreams.set(streamInfo.streamId, stream);
296
- }
297
-
298
- const stream = this._remoteStreams.get(streamInfo.streamId);
299
-
300
- if (!stream?._tracks.includes(track)) {
301
- stream?._tracks.push(track);
302
- }
303
-
304
- return stream;
305
- });
306
-
307
- const eventData = {
308
- streams,
309
- transceiver,
310
- track,
311
- receiver: transceiver.receiver
312
- };
313
-
314
-
315
- this.dispatchEvent(new RTCTrackEvent('track', eventData));
316
-
317
- streams.forEach(stream => {
318
- stream.dispatchEvent(new MediaStreamTrackEvent('addtrack', { track }));
319
- });
320
-
321
- // Dispatch an unmute event for the track.
322
- track._setMutedInternal(false);
323
- }
324
-
325
- log.debug(`${this._pcId} setRemoteDescription OK`);
326
- }
327
-
328
- async addIceCandidate(candidate): Promise<void> {
329
- log.debug(`${this._pcId} addIceCandidate`);
330
-
331
- if (!candidate || !candidate.candidate) {
332
- // XXX end-of candidates is not implemented: https://bugs.chromium.org/p/webrtc/issues/detail?id=9218
333
- return;
334
- }
335
-
336
- if ((candidate.sdpMLineIndex === null ||
337
- candidate.sdpMLineIndex === undefined) &&
338
- (candidate.sdpMid === null ||
339
- candidate.sdpMid === undefined)
340
- ) {
341
- throw new TypeError('`sdpMLineIndex` and `sdpMid` must not be both null or undefined');
342
- }
343
-
344
- const newSdp = await WebRTCModule.peerConnectionAddICECandidate(
345
- this._pcId,
346
- RTCUtil.deepClone(candidate)
347
- );
348
-
349
- this.remoteDescription = new RTCSessionDescription(newSdp);
350
- }
351
-
352
- /**
353
- * @brief Adds a new track to the {@link RTCPeerConnection},
354
- * and indicates that it is contained in the specified {@link MediaStream}s.
355
- * This method has to be synchronous as the W3C API expects a track to be returned
356
- * @param {MediaStreamTrack} track The track to be added
357
- * @param {...MediaStream} streams One or more {@link MediaStream}s the track needs to be added to
358
- * https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtrack
359
- */
360
- addTrack(track: MediaStreamTrack, ...streams: MediaStream[]): RTCRtpSender {
361
- log.debug(`${this._pcId} addTrack`);
362
-
363
- if (this.connectionState === 'closed') {
364
- throw new Error('Peer Connection is closed');
365
- }
366
-
367
- if (this._trackExists(track)) {
368
- throw new Error('Track already exists in a sender');
369
- }
370
-
371
- const streamIds = streams.map(s => s.id);
372
- const result = WebRTCModule.peerConnectionAddTrack(this._pcId, track.id, { streamIds });
373
-
374
- if (result === null) {
375
- throw new Error('Could not add sender');
376
- }
377
-
378
- const { transceiverOrder, transceiver, sender } = result;
379
-
380
- // According to the W3C docs, the sender could have been reused, and
381
- // so we check if that is the case, and update accordingly.
382
- const [ existingSender ] = this
383
- .getSenders()
384
- .filter(s => s.id === sender.id);
385
-
386
- if (existingSender) {
387
- // Update sender
388
- existingSender._track = track;
389
-
390
- // Update the corresponding transceiver as well
391
- const [ existingTransceiver ] = this
392
- .getTransceivers()
393
- .filter(t => t.sender.id === existingSender.id);
394
-
395
- existingTransceiver._direction = transceiver.direction;
396
- existingTransceiver._currentDirection = transceiver.currentDirection;
397
-
398
- return existingSender;
399
- }
400
-
401
- // This is a new transceiver, should create a transceiver for it and add it
402
- const newSender = new RTCRtpSender({ ...transceiver.sender, track });
403
- const remoteTrack = transceiver.receiver.track ? new MediaStreamTrack(transceiver.receiver.track) : null;
404
- const newReceiver = new RTCRtpReceiver({ ...transceiver.receiver, track: remoteTrack });
405
- const newTransceiver = new RTCRtpTransceiver({
406
- ...transceiver,
407
- sender: newSender,
408
- receiver: newReceiver,
409
- });
410
-
411
- this._insertTransceiverSorted(transceiverOrder, newTransceiver);
412
-
413
- return newSender;
414
- }
415
-
416
- addTransceiver(source: 'audio' | 'video' | MediaStreamTrack, init): RTCRtpTransceiver {
417
- log.debug(`${this._pcId} addTransceiver`);
418
-
419
- let src = {};
420
-
421
- if (source === 'audio') {
422
- src = { type: 'audio' };
423
- } else if (source === 'video') {
424
- src = { type: 'video' };
425
- } else {
426
- src = { trackId: source.id };
427
- }
428
-
429
- // Extract the stream ids
430
- if (init && init.streams) {
431
- init.streamIds = init.streams.map(stream => stream.id);
432
- }
433
-
434
- const result = WebRTCModule.peerConnectionAddTransceiver(this._pcId, { ...src, init: { ...init } });
435
-
436
- if (result === null) {
437
- throw new Error('Transceiver could not be added');
438
- }
439
-
440
- const t = result.transceiver;
441
- let track: MediaStreamTrack | null = null;
442
-
443
- if (typeof source === 'string') {
444
- if (t.sender.track) {
445
- track = new MediaStreamTrack(t.sender.track);
446
- }
447
- } else {
448
- // 'source' is a MediaStreamTrack
449
- track = source;
450
- }
451
-
452
- const sender = new RTCRtpSender({ ...t.sender, track });
453
- const remoteTrack = t.receiver.track ? new MediaStreamTrack(t.receiver.track) : null;
454
- const receiver = new RTCRtpReceiver({ ...t.receiver, track: remoteTrack });
455
- const transceiver = new RTCRtpTransceiver({
456
- ...result.transceiver,
457
- sender,
458
- receiver
459
- });
460
-
461
- this._insertTransceiverSorted(result.transceiverOrder, transceiver);
462
-
463
- return transceiver;
464
- }
465
-
466
- removeTrack(sender: RTCRtpSender) {
467
- log.debug(`${this._pcId} removeTrack`);
468
-
469
- if (this._pcId !== sender._peerConnectionId) {
470
- throw new Error('Sender does not belong to this peer connection');
471
- }
472
-
473
- if (this.connectionState === 'closed') {
474
- throw new Error('Peer Connection is closed');
475
- }
476
-
477
- const existingSender = this
478
- .getSenders()
479
- .find(s => s === sender);
480
-
481
- if (!existingSender) {
482
- throw new Error('Sender does not exist');
483
- }
484
-
485
- if (existingSender.track === null) {
486
- return;
487
- }
488
-
489
- // Blocking!
490
- WebRTCModule.peerConnectionRemoveTrack(this._pcId, sender.id);
491
-
492
- existingSender._track = null;
493
-
494
- const [ existingTransceiver ] = this
495
- .getTransceivers()
496
- .filter(t => t.sender.id === existingSender.id);
497
-
498
- existingTransceiver._direction = existingTransceiver.direction === 'sendrecv' ? 'recvonly' : 'inactive';
499
- }
500
-
501
- async getStats(selector?: MediaStreamTrack) {
502
- log.debug(`${this._pcId} getStats`);
503
-
504
- if (!selector) {
505
- const data = await WebRTCModule.peerConnectionGetStats(this._pcId);
506
-
507
- /**
508
- * On both Android and iOS it is faster to construct a single
509
- * JSON string representing the Map of StatsReports and have it
510
- * pass through the React Native bridge rather than the Map of
511
- * StatsReports. While the implementations do try to be faster in
512
- * general, the stress is on being faster to pass through the React
513
- * Native bridge which is a bottleneck that tends to be visible in
514
- * the UI when there is congestion involving UI-related passing.
515
- */
516
- return new Map(JSON.parse(data));
517
- } else {
518
- const senders = this.getSenders().filter(s => s.track === selector);
519
- const receivers = this.getReceivers().filter(r => r.track === selector);
520
- const matches = senders.length + receivers.length;
521
-
522
- if (matches === 0) {
523
- throw new Error('Invalid selector: could not find matching sender / receiver');
524
- } else if (matches > 1) {
525
- throw new Error('Invalid selector: multiple matching senders / receivers');
526
- } else {
527
- const sr = senders[0] || receivers[0];
528
-
529
- return sr.getStats();
530
- }
531
- }
532
- }
533
-
534
- getTransceivers(): RTCRtpTransceiver[] {
535
- return this._transceivers.map(e => e.transceiver);
536
- }
537
-
538
- getSenders(): RTCRtpSender[] {
539
- return this._transceivers.filter(e => !e.transceiver.stopped).map(e => e.transceiver.sender);
540
- }
541
-
542
- getReceivers(): RTCRtpReceiver[] {
543
- return this._transceivers.filter(e => !e.transceiver.stopped).map(e => e.transceiver.receiver);
544
- }
545
-
546
- close(): void {
547
- log.debug(`${this._pcId} close`);
548
-
549
- if (this.connectionState === 'closed') {
550
- return;
551
- }
552
-
553
- WebRTCModule.peerConnectionClose(this._pcId);
554
-
555
- // Mark transceivers as stopped.
556
- this._transceivers.forEach(({ transceiver })=> {
557
- transceiver._setStopped();
558
- });
559
- }
560
-
561
- restartIce(): void {
562
- WebRTCModule.peerConnectionRestartIce(this._pcId);
563
- }
564
-
565
- _registerEvents(): void {
566
- addListener(this, 'peerConnectionOnRenegotiationNeeded', (ev: any) => {
567
- if (ev.pcId !== this._pcId) {
568
- return;
569
- }
570
-
571
- this.dispatchEvent(new Event('negotiationneeded'));
572
- });
573
-
574
- addListener(this, 'peerConnectionIceConnectionChanged', (ev: any) => {
575
- if (ev.pcId !== this._pcId) {
576
- return;
577
- }
578
-
579
- this.iceConnectionState = ev.iceConnectionState;
580
-
581
- this.dispatchEvent(new Event('iceconnectionstatechange'));
582
- });
583
-
584
- addListener(this, 'peerConnectionStateChanged', (ev: any) => {
585
- if (ev.pcId !== this._pcId) {
586
- return;
587
- }
588
-
589
- this.connectionState = ev.connectionState;
590
-
591
- this.dispatchEvent(new Event('connectionstatechange'));
592
-
593
- if (ev.connectionState === 'closed') {
594
- // This PeerConnection is done, clean up.
595
- removeListener(this);
596
-
597
- WebRTCModule.peerConnectionDispose(this._pcId);
598
- }
599
- });
600
-
601
- addListener(this, 'peerConnectionSignalingStateChanged', (ev: any) => {
602
- if (ev.pcId !== this._pcId) {
603
- return;
604
- }
605
-
606
- this.signalingState = ev.signalingState;
607
-
608
- this.dispatchEvent(new Event('signalingstatechange'));
609
- });
610
-
611
- // Consider moving away from this event: https://github.com/WebKit/WebKit/pull/3953
612
- addListener(this, 'peerConnectionOnTrack', (ev: any) => {
613
- if (ev.pcId !== this._pcId) {
614
- return;
615
- }
616
-
617
- log.debug(`${this._pcId} ontrack`);
618
-
619
- // NOTE: We need to make sure the track event fires right before sRD completes,
620
- // so we queue them up here and dispatch the events when sRD fires, but before completing it.
621
- // In the future we should probably implement out own logic and drop this event altogether.
622
- this._pendingTrackEvents.push(ev);
623
- });
624
-
625
- addListener(this, 'peerConnectionOnRemoveTrack', (ev: any) => {
626
- if (ev.pcId !== this._pcId) {
627
- return;
628
- }
629
-
630
- log.debug(`${this._pcId} onremovetrack ${ev.receiverId}`);
631
-
632
- const receiver = this.getReceivers().find(r => r.id === ev.receiverId);
633
- const track = receiver?.track;
634
-
635
- if (receiver && track) {
636
- // As per the spec:
637
- // - Remove the track from any media streams that were previously passed to the `track` event.
638
- // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-removetrack,
639
- // - Mark the track as muted:
640
- // https://w3c.github.io/webrtc-pc/#process-remote-track-removal
641
- for (const stream of this._remoteStreams.values()) {
642
- if (stream._tracks.includes(track)) {
643
- const trackIdx = stream._tracks.indexOf(track);
644
-
645
- log.debug(`${this._pcId} removetrack ${track.id}`);
646
-
647
- stream._tracks.splice(trackIdx, 1);
648
-
649
- stream.dispatchEvent(new MediaStreamTrackEvent('removetrack', { track }));
650
-
651
- // Dispatch a mute event for the track.
652
- track._setMutedInternal(true);
653
- }
654
- }
655
- }
656
- });
657
-
658
- addListener(this, 'peerConnectionGotICECandidate', (ev: any) => {
659
- if (ev.pcId !== this._pcId) {
660
- return;
661
- }
662
-
663
- const sdpInfo = ev.sdp;
664
-
665
- // Can happen when doing a rollback.
666
- if (sdpInfo.type && sdpInfo.sdp) {
667
- this.localDescription = new RTCSessionDescription(sdpInfo);
668
- } else {
669
- this.localDescription = null;
670
- }
671
-
672
- const candidate = new RTCIceCandidate(ev.candidate);
673
-
674
- this.dispatchEvent(new RTCIceCandidateEvent('icecandidate', { candidate }));
675
- });
676
-
677
- addListener(this, 'peerConnectionIceGatheringChanged', (ev: any) => {
678
- if (ev.pcId !== this._pcId) {
679
- return;
680
- }
681
-
682
- this.iceGatheringState = ev.iceGatheringState;
683
-
684
- if (this.iceGatheringState === 'complete') {
685
- const sdpInfo = ev.sdp;
686
-
687
- // Can happen when doing a rollback.
688
- if (sdpInfo.type && sdpInfo.sdp) {
689
- this.localDescription = new RTCSessionDescription(sdpInfo);
690
- } else {
691
- this.localDescription = null;
692
- }
693
-
694
- this.dispatchEvent(new RTCIceCandidateEvent('icecandidate', { candidate: null }));
695
- }
696
-
697
- this.dispatchEvent(new Event('icegatheringstatechange'));
698
- });
699
-
700
- addListener(this, 'peerConnectionDidOpenDataChannel', (ev: any) => {
701
- if (ev.pcId !== this._pcId) {
702
- return;
703
- }
704
-
705
- const channel = new RTCDataChannel(ev.dataChannel);
706
-
707
- this.dispatchEvent(new RTCDataChannelEvent('datachannel', { channel }));
708
-
709
- // Send 'open' event. Native doesn't update the state since it's already
710
- // set at this point.
711
- channel.dispatchEvent(new RTCDataChannelEvent('open', { channel }));
712
- });
713
-
714
- addListener(this, 'mediaStreamTrackMuteChanged', (ev: any) => {
715
- if (ev.pcId !== this._pcId) {
716
- return;
717
- }
718
-
719
- const [
720
- track
721
- ] = this.getReceivers().map(r => r.track).filter(t => t?.id === ev.trackId);
722
-
723
- if (track) {
724
- track._setMutedInternal(ev.muted);
725
- }
726
- });
727
- }
728
-
729
- /**
730
- * Creates a new RTCDataChannel object with the given label. The
731
- * RTCDataChannelInit dictionary can be used to configure properties of the
732
- * underlying channel such as data reliability.
733
- *
734
- * @param {string} label - the value with which the label attribute of the new
735
- * instance is to be initialized
736
- * @param {RTCDataChannelInit} dataChannelDict - an optional dictionary of
737
- * values with which to initialize corresponding attributes of the new
738
- * instance such as id
739
- */
740
- createDataChannel(label: string, dataChannelDict?: RTCDataChannelInit): RTCDataChannel {
741
- if (arguments.length === 0) {
742
- throw new TypeError('1 argument required, but 0 present');
743
- }
744
-
745
- if (dataChannelDict && 'id' in dataChannelDict) {
746
- const id = dataChannelDict.id;
747
-
748
- if (typeof id !== 'number') {
749
- throw new TypeError('DataChannel id must be a number: ' + id);
750
- }
751
- }
752
-
753
- const channelInfo = WebRTCModule.createDataChannel(this._pcId, String(label), dataChannelDict);
754
-
755
- if (channelInfo === null) {
756
- throw new TypeError('Failed to create new DataChannel');
757
- }
758
-
759
- return new RTCDataChannel(channelInfo);
760
- }
761
-
762
- /**
763
- * Check whether a media stream track exists already in a sender.
764
- * See https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtrack for more information
765
- */
766
- _trackExists(track: MediaStreamTrack): boolean {
767
- const [ sender ] = this
768
- .getSenders()
769
- .filter(
770
- sender => sender.track?.id === track.id
771
- );
772
-
773
- return sender? true : false;
774
- }
775
-
776
- /**
777
- * Updates transceivers after offer/answer updates if necessary.
778
- */
779
- _updateTransceivers(transceiverUpdates, removeStopped = false) {
780
- for (const update of transceiverUpdates) {
781
- const [ transceiver ] = this
782
- .getTransceivers()
783
- .filter(t => t.sender.id === update.transceiverId);
784
-
785
- if (!transceiver) {
786
- continue;
787
- }
788
-
789
- if (update.currentDirection) {
790
- transceiver._currentDirection = update.currentDirection;
791
- }
792
-
793
- transceiver._mid = update.mid;
794
- transceiver._stopped = Boolean(update.isStopped);
795
- transceiver._sender._rtpParameters = new RTCRtpSendParameters(update.senderRtpParameters);
796
- transceiver._receiver._rtpParameters = new RTCRtpReceiveParameters(update.receiverRtpParameters);
797
- }
798
-
799
- if (removeStopped) {
800
- const stopped = this.getTransceivers().filter(t => t.stopped);
801
- const newTransceivers = this._transceivers.filter(t => !stopped.includes(t.transceiver));
802
-
803
- this._transceivers = newTransceivers;
804
- }
805
- }
806
-
807
- /**
808
- * Inserts transceiver into the transceiver array in the order they are created (timestamp).
809
- * @param order an index that refers to when it it was created relatively.
810
- * @param transceiver the transceiver object to be inserted.
811
- */
812
- _insertTransceiverSorted(order: number, transceiver: RTCRtpTransceiver) {
813
- this._transceivers.push({ order, transceiver });
814
- this._transceivers.sort((a, b) => a.order - b.order);
815
- }
816
- }
817
-
818
- /**
819
- * Define the `onxxx` event handlers.
820
- */
821
- const proto = RTCPeerConnection.prototype;
822
-
823
- defineEventAttribute(proto, 'connectionstatechange');
824
- defineEventAttribute(proto, 'icecandidate');
825
- defineEventAttribute(proto, 'icecandidateerror');
826
- defineEventAttribute(proto, 'iceconnectionstatechange');
827
- defineEventAttribute(proto, 'icegatheringstatechange');
828
- defineEventAttribute(proto, 'negotiationneeded');
829
- defineEventAttribute(proto, 'signalingstatechange');
830
- defineEventAttribute(proto, 'datachannel');
831
- defineEventAttribute(proto, 'track');
832
- defineEventAttribute(proto, 'error');
1
+ import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';
2
+ import { NativeModules } from 'react-native';
3
+
4
+ import { addListener, removeListener } from './EventEmitter';
5
+ import Logger from './Logger';
6
+ import MediaStream from './MediaStream';
7
+ import MediaStreamTrack from './MediaStreamTrack';
8
+ import MediaStreamTrackEvent from './MediaStreamTrackEvent';
9
+ import RTCDataChannel from './RTCDataChannel';
10
+ import RTCDataChannelEvent from './RTCDataChannelEvent';
11
+ import RTCIceCandidate from './RTCIceCandidate';
12
+ import RTCIceCandidateEvent from './RTCIceCandidateEvent';
13
+ import RTCRtpReceiveParameters from './RTCRtpReceiveParameters';
14
+ import RTCRtpReceiver from './RTCRtpReceiver';
15
+ import RTCRtpSendParameters from './RTCRtpSendParameters';
16
+ import RTCRtpSender from './RTCRtpSender';
17
+ import RTCRtpTransceiver from './RTCRtpTransceiver';
18
+ import RTCSessionDescription, { RTCSessionDescriptionInit } from './RTCSessionDescription';
19
+ import RTCTrackEvent from './RTCTrackEvent';
20
+ import * as RTCUtil from './RTCUtil';
21
+ import { RTCOfferOptions } from './RTCUtil';
22
+
23
+ const log = new Logger('pc');
24
+ const { WebRTCModule } = NativeModules;
25
+
26
+ type RTCSignalingState =
27
+ | 'stable'
28
+ | 'have-local-offer'
29
+ | 'have-remote-offer'
30
+ | 'have-local-pranswer'
31
+ | 'have-remote-pranswer'
32
+ | 'closed';
33
+
34
+ type RTCIceGatheringState = 'new' | 'gathering' | 'complete';
35
+
36
+ type RTCPeerConnectionState = 'new' | 'connecting' | 'connected' | 'disconnected' | 'failed' | 'closed';
37
+
38
+ type RTCIceConnectionState = 'new' | 'checking' | 'connected' | 'completed' | 'failed' | 'disconnected' | 'closed';
39
+
40
+ type RTCDataChannelInit = {
41
+ ordered?: boolean,
42
+ maxPacketLifeTime?: number,
43
+ maxRetransmits?: number,
44
+ protocol?: string,
45
+ negotiated?: boolean,
46
+ id?: number
47
+ };
48
+
49
+ type RTCIceServer = {
50
+ credential?: string,
51
+ url?: string, // Deprecated.
52
+ urls?: string | string[],
53
+ username?: string
54
+ };
55
+
56
+ type RTCConfiguration = {
57
+ bundlePolicy?: 'balanced' | 'max-compat' | 'max-bundle',
58
+ iceCandidatePoolSize?: number,
59
+ iceServers?: RTCIceServer[],
60
+ iceTransportPolicy?: 'all' | 'relay',
61
+ rtcpMuxPolicy?: 'negotiate' | 'require'
62
+ };
63
+
64
+ type RTCPeerConnectionEventMap = {
65
+ connectionstatechange: Event<'connectionstatechange'>
66
+ icecandidate: RTCIceCandidateEvent<'icecandidate'>
67
+ icecandidateerror: RTCIceCandidateEvent<'icecandidateerror'>
68
+ iceconnectionstatechange: Event<'iceconnectionstatechange'>
69
+ icegatheringstatechange: Event<'icegatheringstatechange'>
70
+ negotiationneeded: Event<'negotiationneeded'>
71
+ signalingstatechange: Event<'signalingstatechange'>
72
+ datachannel: RTCDataChannelEvent<'datachannel'>
73
+ track: RTCTrackEvent<'track'>
74
+ error: Event<'error'>
75
+ }
76
+
77
+ let nextPeerConnectionId = 0;
78
+
79
+ export default class RTCPeerConnection extends EventTarget<RTCPeerConnectionEventMap> {
80
+ localDescription: RTCSessionDescription | null = null;
81
+ remoteDescription: RTCSessionDescription | null = null;
82
+ signalingState: RTCSignalingState = 'stable';
83
+ iceGatheringState: RTCIceGatheringState = 'new';
84
+ connectionState: RTCPeerConnectionState = 'new';
85
+ iceConnectionState: RTCIceConnectionState = 'new';
86
+
87
+ _pcId: number;
88
+ _transceivers: { order: number, transceiver: RTCRtpTransceiver }[];
89
+ _remoteStreams: Map<string, MediaStream>;
90
+ _pendingTrackEvents: any[];
91
+
92
+ constructor(configuration?: RTCConfiguration) {
93
+ super();
94
+
95
+ this._pcId = nextPeerConnectionId++;
96
+
97
+ // Sanitize ICE servers.
98
+ if (configuration) {
99
+ const servers = configuration?.iceServers ?? [];
100
+
101
+ for (const server of servers) {
102
+ let urls = server.url || server.urls;
103
+
104
+ delete server.url;
105
+ delete server.urls;
106
+
107
+ if (!urls) {
108
+ continue;
109
+ }
110
+
111
+ if (!Array.isArray(urls)) {
112
+ urls = [ urls ];
113
+ }
114
+
115
+ // Native WebRTC does case sensitive parsing.
116
+ server.urls = urls.map(url => url.toLowerCase());
117
+ }
118
+
119
+ // Filter out bogus servers.
120
+ configuration.iceServers = servers.filter(s => s.urls);
121
+ }
122
+
123
+ if (!WebRTCModule.peerConnectionInit(configuration, this._pcId)) {
124
+ throw new Error('Failed to initialize PeerConnection, check the native logs!');
125
+ }
126
+
127
+ this._transceivers = [];
128
+ this._remoteStreams = new Map();
129
+ this._pendingTrackEvents = [];
130
+
131
+ this._registerEvents();
132
+
133
+ log.debug(`${this._pcId} ctor`);
134
+ }
135
+
136
+ async createOffer(options?:RTCOfferOptions) {
137
+ log.debug(`${this._pcId} createOffer`);
138
+
139
+ const {
140
+ sdpInfo,
141
+ newTransceivers,
142
+ transceiversInfo
143
+ } = await WebRTCModule.peerConnectionCreateOffer(this._pcId, RTCUtil.normalizeOfferOptions(options));
144
+
145
+ log.debug(`${this._pcId} createOffer OK`);
146
+
147
+ newTransceivers?.forEach(t => {
148
+ const { transceiverOrder, transceiver } = t;
149
+ const newSender = new RTCRtpSender({ ...transceiver.sender, track: null });
150
+ const remoteTrack
151
+ = transceiver.receiver.track ? new MediaStreamTrack(transceiver.receiver.track) : null;
152
+ const newReceiver = new RTCRtpReceiver({ ...transceiver.receiver, track: remoteTrack });
153
+ const newTransceiver = new RTCRtpTransceiver({
154
+ ...transceiver,
155
+ sender: newSender,
156
+ receiver: newReceiver,
157
+ });
158
+
159
+ this._insertTransceiverSorted(transceiverOrder, newTransceiver);
160
+ });
161
+
162
+ this._updateTransceivers(transceiversInfo);
163
+
164
+ return sdpInfo;
165
+ }
166
+
167
+ async createAnswer() {
168
+ log.debug(`${this._pcId} createAnswer`);
169
+
170
+ const {
171
+ sdpInfo,
172
+ transceiversInfo
173
+ } = await WebRTCModule.peerConnectionCreateAnswer(this._pcId, {});
174
+
175
+ this._updateTransceivers(transceiversInfo);
176
+
177
+ return sdpInfo;
178
+ }
179
+
180
+ setConfiguration(configuration): void {
181
+ WebRTCModule.peerConnectionSetConfiguration(configuration, this._pcId);
182
+ }
183
+
184
+ async setLocalDescription(sessionDescription?: RTCSessionDescription | RTCSessionDescriptionInit): Promise<void> {
185
+ log.debug(`${this._pcId} setLocalDescription`);
186
+
187
+ let desc;
188
+
189
+ if (sessionDescription) {
190
+ desc = {
191
+ type: sessionDescription.type,
192
+ sdp: sessionDescription.sdp ?? ''
193
+ };
194
+
195
+ if (!RTCUtil.isSdpTypeValid(desc.type)) {
196
+ throw new Error(`Invalid session description: invalid type: ${desc.type}`);
197
+ }
198
+ } else {
199
+ desc = null;
200
+ }
201
+
202
+ const {
203
+ sdpInfo,
204
+ transceiversInfo
205
+ } = await WebRTCModule.peerConnectionSetLocalDescription(this._pcId, desc);
206
+
207
+ if (sdpInfo.type && sdpInfo.sdp) {
208
+ this.localDescription = new RTCSessionDescription(sdpInfo);
209
+ } else {
210
+ this.localDescription = null;
211
+ }
212
+
213
+ this._updateTransceivers(transceiversInfo, /* removeStopped */ desc?.type === 'answer');
214
+
215
+ log.debug(`${this._pcId} setLocalDescription OK`);
216
+ }
217
+
218
+ async setRemoteDescription(sessionDescription: RTCSessionDescription | RTCSessionDescriptionInit): Promise<void> {
219
+ log.debug(`${this._pcId} setRemoteDescription`);
220
+
221
+ if (!sessionDescription) {
222
+ return Promise.reject(new Error('No session description provided'));
223
+ }
224
+
225
+ const desc = {
226
+ type: sessionDescription.type,
227
+ sdp: sessionDescription.sdp ?? ''
228
+ };
229
+
230
+ if (!RTCUtil.isSdpTypeValid(desc.type ?? '')) {
231
+ throw new Error(`Invalid session description: invalid type: ${desc.type}`);
232
+ }
233
+
234
+ const {
235
+ sdpInfo,
236
+ newTransceivers,
237
+ transceiversInfo
238
+ } = await WebRTCModule.peerConnectionSetRemoteDescription(this._pcId, desc);
239
+
240
+ if (sdpInfo.type && sdpInfo.sdp) {
241
+ this.remoteDescription = new RTCSessionDescription(sdpInfo);
242
+ } else {
243
+ this.remoteDescription = null;
244
+ }
245
+
246
+ newTransceivers?.forEach(t => {
247
+ const { transceiverOrder, transceiver } = t;
248
+ const newSender = new RTCRtpSender({ ...transceiver.sender, track: null });
249
+ const remoteTrack
250
+ = transceiver.receiver.track ? new MediaStreamTrack(transceiver.receiver.track) : null;
251
+ const newReceiver = new RTCRtpReceiver({ ...transceiver.receiver, track: remoteTrack });
252
+ const newTransceiver = new RTCRtpTransceiver({
253
+ ...transceiver,
254
+ sender: newSender,
255
+ receiver: newReceiver,
256
+ });
257
+
258
+ this._insertTransceiverSorted(transceiverOrder, newTransceiver);
259
+ });
260
+
261
+ this._updateTransceivers(transceiversInfo, /* removeStopped */ desc.type === 'answer');
262
+
263
+ // Fire track events. They must fire before sRD resolves.
264
+ const pendingTrackEvents = this._pendingTrackEvents;
265
+
266
+ this._pendingTrackEvents = [];
267
+
268
+ for (const ev of pendingTrackEvents) {
269
+ const [ transceiver ] = this
270
+ .getTransceivers()
271
+ .filter(t => t.receiver.id === ev.receiver.id);
272
+
273
+ // We need to fire this event for an existing track sometimes, like
274
+ // when the transceiver direction (on the sending side) switches from
275
+ // sendrecv to recvonly and then back.
276
+
277
+ // @ts-ignore
278
+ const track: MediaStreamTrack = transceiver.receiver.track;
279
+
280
+ transceiver._mid = ev.transceiver.mid;
281
+ transceiver._currentDirection = ev.transceiver.currentDirection;
282
+ transceiver._direction = ev.transceiver.direction;
283
+
284
+ // Get the stream object from the event. Create if necessary.
285
+ const streams: MediaStream[] = ev.streams.map(streamInfo => {
286
+ // Here we are making sure that we don't create stream objects that already exist
287
+ // So that event listeners do get the same object if it has been created before.
288
+ if (!this._remoteStreams.has(streamInfo.streamId)) {
289
+ const stream = new MediaStream({
290
+ streamId: streamInfo.streamId,
291
+ streamReactTag: streamInfo.streamReactTag,
292
+ tracks: []
293
+ });
294
+
295
+ this._remoteStreams.set(streamInfo.streamId, stream);
296
+ }
297
+
298
+ const stream = this._remoteStreams.get(streamInfo.streamId);
299
+
300
+ if (!stream?._tracks.includes(track)) {
301
+ stream?._tracks.push(track);
302
+ }
303
+
304
+ return stream;
305
+ });
306
+
307
+ const eventData = {
308
+ streams,
309
+ transceiver,
310
+ track,
311
+ receiver: transceiver.receiver
312
+ };
313
+
314
+
315
+ this.dispatchEvent(new RTCTrackEvent('track', eventData));
316
+
317
+ streams.forEach(stream => {
318
+ stream.dispatchEvent(new MediaStreamTrackEvent('addtrack', { track }));
319
+ });
320
+
321
+ // Dispatch an unmute event for the track.
322
+ track._setMutedInternal(false);
323
+ }
324
+
325
+ log.debug(`${this._pcId} setRemoteDescription OK`);
326
+ }
327
+
328
+ async addIceCandidate(candidate): Promise<void> {
329
+ log.debug(`${this._pcId} addIceCandidate`);
330
+
331
+ if (!candidate || !candidate.candidate) {
332
+ // XXX end-of candidates is not implemented: https://bugs.chromium.org/p/webrtc/issues/detail?id=9218
333
+ return;
334
+ }
335
+
336
+ if ((candidate.sdpMLineIndex === null ||
337
+ candidate.sdpMLineIndex === undefined) &&
338
+ (candidate.sdpMid === null ||
339
+ candidate.sdpMid === undefined)
340
+ ) {
341
+ throw new TypeError('`sdpMLineIndex` and `sdpMid` must not be both null or undefined');
342
+ }
343
+
344
+ const newSdp = await WebRTCModule.peerConnectionAddICECandidate(
345
+ this._pcId,
346
+ RTCUtil.deepClone(candidate)
347
+ );
348
+
349
+ this.remoteDescription = new RTCSessionDescription(newSdp);
350
+ }
351
+
352
+ /**
353
+ * @brief Adds a new track to the {@link RTCPeerConnection},
354
+ * and indicates that it is contained in the specified {@link MediaStream}s.
355
+ * This method has to be synchronous as the W3C API expects a track to be returned
356
+ * @param {MediaStreamTrack} track The track to be added
357
+ * @param {...MediaStream} streams One or more {@link MediaStream}s the track needs to be added to
358
+ * https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtrack
359
+ */
360
+ addTrack(track: MediaStreamTrack, ...streams: MediaStream[]): RTCRtpSender {
361
+ log.debug(`${this._pcId} addTrack`);
362
+
363
+ if (this.connectionState === 'closed') {
364
+ throw new Error('Peer Connection is closed');
365
+ }
366
+
367
+ if (this._trackExists(track)) {
368
+ throw new Error('Track already exists in a sender');
369
+ }
370
+
371
+ const streamIds = streams.map(s => s.id);
372
+ const result = WebRTCModule.peerConnectionAddTrack(this._pcId, track.id, { streamIds });
373
+
374
+ if (result === null) {
375
+ throw new Error('Could not add sender');
376
+ }
377
+
378
+ const { transceiverOrder, transceiver, sender } = result;
379
+
380
+ // According to the W3C docs, the sender could have been reused, and
381
+ // so we check if that is the case, and update accordingly.
382
+ const [ existingSender ] = this
383
+ .getSenders()
384
+ .filter(s => s.id === sender.id);
385
+
386
+ if (existingSender) {
387
+ // Update sender
388
+ existingSender._track = track;
389
+
390
+ // Update the corresponding transceiver as well
391
+ const [ existingTransceiver ] = this
392
+ .getTransceivers()
393
+ .filter(t => t.sender.id === existingSender.id);
394
+
395
+ existingTransceiver._direction = transceiver.direction;
396
+ existingTransceiver._currentDirection = transceiver.currentDirection;
397
+
398
+ return existingSender;
399
+ }
400
+
401
+ // This is a new transceiver, should create a transceiver for it and add it
402
+ const newSender = new RTCRtpSender({ ...transceiver.sender, track });
403
+ const remoteTrack = transceiver.receiver.track ? new MediaStreamTrack(transceiver.receiver.track) : null;
404
+ const newReceiver = new RTCRtpReceiver({ ...transceiver.receiver, track: remoteTrack });
405
+ const newTransceiver = new RTCRtpTransceiver({
406
+ ...transceiver,
407
+ sender: newSender,
408
+ receiver: newReceiver,
409
+ });
410
+
411
+ this._insertTransceiverSorted(transceiverOrder, newTransceiver);
412
+
413
+ return newSender;
414
+ }
415
+
416
+ addTransceiver(source: 'audio' | 'video' | MediaStreamTrack, init): RTCRtpTransceiver {
417
+ log.debug(`${this._pcId} addTransceiver`);
418
+
419
+ let src = {};
420
+
421
+ if (source === 'audio') {
422
+ src = { type: 'audio' };
423
+ } else if (source === 'video') {
424
+ src = { type: 'video' };
425
+ } else {
426
+ src = { trackId: source.id };
427
+ }
428
+
429
+ // Extract the stream ids
430
+ if (init && init.streams) {
431
+ init.streamIds = init.streams.map(stream => stream.id);
432
+ }
433
+
434
+ const result = WebRTCModule.peerConnectionAddTransceiver(this._pcId, { ...src, init: { ...init } });
435
+
436
+ if (result === null) {
437
+ throw new Error('Transceiver could not be added');
438
+ }
439
+
440
+ const t = result.transceiver;
441
+ let track: MediaStreamTrack | null = null;
442
+
443
+ if (typeof source === 'string') {
444
+ if (t.sender.track) {
445
+ track = new MediaStreamTrack(t.sender.track);
446
+ }
447
+ } else {
448
+ // 'source' is a MediaStreamTrack
449
+ track = source;
450
+ }
451
+
452
+ const sender = new RTCRtpSender({ ...t.sender, track });
453
+ const remoteTrack = t.receiver.track ? new MediaStreamTrack(t.receiver.track) : null;
454
+ const receiver = new RTCRtpReceiver({ ...t.receiver, track: remoteTrack });
455
+ const transceiver = new RTCRtpTransceiver({
456
+ ...result.transceiver,
457
+ sender,
458
+ receiver
459
+ });
460
+
461
+ this._insertTransceiverSorted(result.transceiverOrder, transceiver);
462
+
463
+ return transceiver;
464
+ }
465
+
466
+ removeTrack(sender: RTCRtpSender) {
467
+ log.debug(`${this._pcId} removeTrack`);
468
+
469
+ if (this._pcId !== sender._peerConnectionId) {
470
+ throw new Error('Sender does not belong to this peer connection');
471
+ }
472
+
473
+ if (this.connectionState === 'closed') {
474
+ throw new Error('Peer Connection is closed');
475
+ }
476
+
477
+ const existingSender = this
478
+ .getSenders()
479
+ .find(s => s === sender);
480
+
481
+ if (!existingSender) {
482
+ throw new Error('Sender does not exist');
483
+ }
484
+
485
+ if (existingSender.track === null) {
486
+ return;
487
+ }
488
+
489
+ // Blocking!
490
+ WebRTCModule.peerConnectionRemoveTrack(this._pcId, sender.id);
491
+
492
+ existingSender._track = null;
493
+
494
+ const [ existingTransceiver ] = this
495
+ .getTransceivers()
496
+ .filter(t => t.sender.id === existingSender.id);
497
+
498
+ existingTransceiver._direction = existingTransceiver.direction === 'sendrecv' ? 'recvonly' : 'inactive';
499
+ }
500
+
501
+ async getStats(selector?: MediaStreamTrack) {
502
+ log.debug(`${this._pcId} getStats`);
503
+
504
+ if (!selector) {
505
+ const data = await WebRTCModule.peerConnectionGetStats(this._pcId);
506
+
507
+ /**
508
+ * On both Android and iOS it is faster to construct a single
509
+ * JSON string representing the Map of StatsReports and have it
510
+ * pass through the React Native bridge rather than the Map of
511
+ * StatsReports. While the implementations do try to be faster in
512
+ * general, the stress is on being faster to pass through the React
513
+ * Native bridge which is a bottleneck that tends to be visible in
514
+ * the UI when there is congestion involving UI-related passing.
515
+ */
516
+ return new Map(JSON.parse(data));
517
+ } else {
518
+ const senders = this.getSenders().filter(s => s.track === selector);
519
+ const receivers = this.getReceivers().filter(r => r.track === selector);
520
+ const matches = senders.length + receivers.length;
521
+
522
+ if (matches === 0) {
523
+ throw new Error('Invalid selector: could not find matching sender / receiver');
524
+ } else if (matches > 1) {
525
+ throw new Error('Invalid selector: multiple matching senders / receivers');
526
+ } else {
527
+ const sr = senders[0] || receivers[0];
528
+
529
+ return sr.getStats();
530
+ }
531
+ }
532
+ }
533
+
534
+ getTransceivers(): RTCRtpTransceiver[] {
535
+ return this._transceivers.map(e => e.transceiver);
536
+ }
537
+
538
+ getSenders(): RTCRtpSender[] {
539
+ return this._transceivers.filter(e => !e.transceiver.stopped).map(e => e.transceiver.sender);
540
+ }
541
+
542
+ getReceivers(): RTCRtpReceiver[] {
543
+ return this._transceivers.filter(e => !e.transceiver.stopped).map(e => e.transceiver.receiver);
544
+ }
545
+
546
+ close(): void {
547
+ log.debug(`${this._pcId} close`);
548
+
549
+ if (this.connectionState === 'closed') {
550
+ return;
551
+ }
552
+
553
+ WebRTCModule.peerConnectionClose(this._pcId);
554
+
555
+ // Mark transceivers as stopped.
556
+ this._transceivers.forEach(({ transceiver })=> {
557
+ transceiver._setStopped();
558
+ });
559
+ }
560
+
561
+ restartIce(): void {
562
+ WebRTCModule.peerConnectionRestartIce(this._pcId);
563
+ }
564
+
565
+ _registerEvents(): void {
566
+ addListener(this, 'peerConnectionOnRenegotiationNeeded', (ev: any) => {
567
+ if (ev.pcId !== this._pcId) {
568
+ return;
569
+ }
570
+
571
+ this.dispatchEvent(new Event('negotiationneeded'));
572
+ });
573
+
574
+ addListener(this, 'peerConnectionIceConnectionChanged', (ev: any) => {
575
+ if (ev.pcId !== this._pcId) {
576
+ return;
577
+ }
578
+
579
+ this.iceConnectionState = ev.iceConnectionState;
580
+
581
+ this.dispatchEvent(new Event('iceconnectionstatechange'));
582
+ });
583
+
584
+ addListener(this, 'peerConnectionStateChanged', (ev: any) => {
585
+ if (ev.pcId !== this._pcId) {
586
+ return;
587
+ }
588
+
589
+ this.connectionState = ev.connectionState;
590
+
591
+ this.dispatchEvent(new Event('connectionstatechange'));
592
+
593
+ if (ev.connectionState === 'closed') {
594
+ // This PeerConnection is done, clean up.
595
+ removeListener(this);
596
+
597
+ WebRTCModule.peerConnectionDispose(this._pcId);
598
+ }
599
+ });
600
+
601
+ addListener(this, 'peerConnectionSignalingStateChanged', (ev: any) => {
602
+ if (ev.pcId !== this._pcId) {
603
+ return;
604
+ }
605
+
606
+ this.signalingState = ev.signalingState;
607
+
608
+ this.dispatchEvent(new Event('signalingstatechange'));
609
+ });
610
+
611
+ // Consider moving away from this event: https://github.com/WebKit/WebKit/pull/3953
612
+ addListener(this, 'peerConnectionOnTrack', (ev: any) => {
613
+ if (ev.pcId !== this._pcId) {
614
+ return;
615
+ }
616
+
617
+ log.debug(`${this._pcId} ontrack`);
618
+
619
+ // NOTE: We need to make sure the track event fires right before sRD completes,
620
+ // so we queue them up here and dispatch the events when sRD fires, but before completing it.
621
+ // In the future we should probably implement out own logic and drop this event altogether.
622
+ this._pendingTrackEvents.push(ev);
623
+ });
624
+
625
+ addListener(this, 'peerConnectionOnRemoveTrack', (ev: any) => {
626
+ if (ev.pcId !== this._pcId) {
627
+ return;
628
+ }
629
+
630
+ log.debug(`${this._pcId} onremovetrack ${ev.receiverId}`);
631
+
632
+ const receiver = this.getReceivers().find(r => r.id === ev.receiverId);
633
+ const track = receiver?.track;
634
+
635
+ if (receiver && track) {
636
+ // As per the spec:
637
+ // - Remove the track from any media streams that were previously passed to the `track` event.
638
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-removetrack,
639
+ // - Mark the track as muted:
640
+ // https://w3c.github.io/webrtc-pc/#process-remote-track-removal
641
+ for (const stream of this._remoteStreams.values()) {
642
+ if (stream._tracks.includes(track)) {
643
+ const trackIdx = stream._tracks.indexOf(track);
644
+
645
+ log.debug(`${this._pcId} removetrack ${track.id}`);
646
+
647
+ stream._tracks.splice(trackIdx, 1);
648
+
649
+ stream.dispatchEvent(new MediaStreamTrackEvent('removetrack', { track }));
650
+
651
+ // Dispatch a mute event for the track.
652
+ track._setMutedInternal(true);
653
+ }
654
+ }
655
+ }
656
+ });
657
+
658
+ addListener(this, 'peerConnectionGotICECandidate', (ev: any) => {
659
+ if (ev.pcId !== this._pcId) {
660
+ return;
661
+ }
662
+
663
+ const sdpInfo = ev.sdp;
664
+
665
+ // Can happen when doing a rollback.
666
+ if (sdpInfo.type && sdpInfo.sdp) {
667
+ this.localDescription = new RTCSessionDescription(sdpInfo);
668
+ } else {
669
+ this.localDescription = null;
670
+ }
671
+
672
+ const candidate = new RTCIceCandidate(ev.candidate);
673
+
674
+ this.dispatchEvent(new RTCIceCandidateEvent('icecandidate', { candidate }));
675
+ });
676
+
677
+ addListener(this, 'peerConnectionIceGatheringChanged', (ev: any) => {
678
+ if (ev.pcId !== this._pcId) {
679
+ return;
680
+ }
681
+
682
+ this.iceGatheringState = ev.iceGatheringState;
683
+
684
+ if (this.iceGatheringState === 'complete') {
685
+ const sdpInfo = ev.sdp;
686
+
687
+ // Can happen when doing a rollback.
688
+ if (sdpInfo.type && sdpInfo.sdp) {
689
+ this.localDescription = new RTCSessionDescription(sdpInfo);
690
+ } else {
691
+ this.localDescription = null;
692
+ }
693
+
694
+ this.dispatchEvent(new RTCIceCandidateEvent('icecandidate', { candidate: null }));
695
+ }
696
+
697
+ this.dispatchEvent(new Event('icegatheringstatechange'));
698
+ });
699
+
700
+ addListener(this, 'peerConnectionDidOpenDataChannel', (ev: any) => {
701
+ if (ev.pcId !== this._pcId) {
702
+ return;
703
+ }
704
+
705
+ const channel = new RTCDataChannel(ev.dataChannel);
706
+
707
+ this.dispatchEvent(new RTCDataChannelEvent('datachannel', { channel }));
708
+
709
+ // Send 'open' event. Native doesn't update the state since it's already
710
+ // set at this point.
711
+ channel.dispatchEvent(new RTCDataChannelEvent('open', { channel }));
712
+ });
713
+
714
+ addListener(this, 'mediaStreamTrackMuteChanged', (ev: any) => {
715
+ if (ev.pcId !== this._pcId) {
716
+ return;
717
+ }
718
+
719
+ const [
720
+ track
721
+ ] = this.getReceivers().map(r => r.track).filter(t => t?.id === ev.trackId);
722
+
723
+ if (track) {
724
+ track._setMutedInternal(ev.muted);
725
+ }
726
+ });
727
+ }
728
+
729
+ /**
730
+ * Creates a new RTCDataChannel object with the given label. The
731
+ * RTCDataChannelInit dictionary can be used to configure properties of the
732
+ * underlying channel such as data reliability.
733
+ *
734
+ * @param {string} label - the value with which the label attribute of the new
735
+ * instance is to be initialized
736
+ * @param {RTCDataChannelInit} dataChannelDict - an optional dictionary of
737
+ * values with which to initialize corresponding attributes of the new
738
+ * instance such as id
739
+ */
740
+ createDataChannel(label: string, dataChannelDict?: RTCDataChannelInit): RTCDataChannel {
741
+ if (arguments.length === 0) {
742
+ throw new TypeError('1 argument required, but 0 present');
743
+ }
744
+
745
+ if (dataChannelDict && 'id' in dataChannelDict) {
746
+ const id = dataChannelDict.id;
747
+
748
+ if (typeof id !== 'number') {
749
+ throw new TypeError('DataChannel id must be a number: ' + id);
750
+ }
751
+ }
752
+
753
+ const channelInfo = WebRTCModule.createDataChannel(this._pcId, String(label), dataChannelDict);
754
+
755
+ if (channelInfo === null) {
756
+ throw new TypeError('Failed to create new DataChannel');
757
+ }
758
+
759
+ return new RTCDataChannel(channelInfo);
760
+ }
761
+
762
+ /**
763
+ * Check whether a media stream track exists already in a sender.
764
+ * See https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtrack for more information
765
+ */
766
+ _trackExists(track: MediaStreamTrack): boolean {
767
+ const [ sender ] = this
768
+ .getSenders()
769
+ .filter(
770
+ sender => sender.track?.id === track.id
771
+ );
772
+
773
+ return sender? true : false;
774
+ }
775
+
776
+ /**
777
+ * Updates transceivers after offer/answer updates if necessary.
778
+ */
779
+ _updateTransceivers(transceiverUpdates, removeStopped = false) {
780
+ for (const update of transceiverUpdates) {
781
+ const [ transceiver ] = this
782
+ .getTransceivers()
783
+ .filter(t => t.sender.id === update.transceiverId);
784
+
785
+ if (!transceiver) {
786
+ continue;
787
+ }
788
+
789
+ if (update.currentDirection) {
790
+ transceiver._currentDirection = update.currentDirection;
791
+ }
792
+
793
+ transceiver._mid = update.mid;
794
+ transceiver._stopped = Boolean(update.isStopped);
795
+ transceiver._sender._rtpParameters = new RTCRtpSendParameters(update.senderRtpParameters);
796
+ transceiver._receiver._rtpParameters = new RTCRtpReceiveParameters(update.receiverRtpParameters);
797
+ }
798
+
799
+ if (removeStopped) {
800
+ const stopped = this.getTransceivers().filter(t => t.stopped);
801
+ const newTransceivers = this._transceivers.filter(t => !stopped.includes(t.transceiver));
802
+
803
+ this._transceivers = newTransceivers;
804
+ }
805
+ }
806
+
807
+ /**
808
+ * Inserts transceiver into the transceiver array in the order they are created (timestamp).
809
+ * @param order an index that refers to when it it was created relatively.
810
+ * @param transceiver the transceiver object to be inserted.
811
+ */
812
+ _insertTransceiverSorted(order: number, transceiver: RTCRtpTransceiver) {
813
+ this._transceivers.push({ order, transceiver });
814
+ this._transceivers.sort((a, b) => a.order - b.order);
815
+ }
816
+ }
817
+
818
+ /**
819
+ * Define the `onxxx` event handlers.
820
+ */
821
+ const proto = RTCPeerConnection.prototype;
822
+
823
+ defineEventAttribute(proto, 'connectionstatechange');
824
+ defineEventAttribute(proto, 'icecandidate');
825
+ defineEventAttribute(proto, 'icecandidateerror');
826
+ defineEventAttribute(proto, 'iceconnectionstatechange');
827
+ defineEventAttribute(proto, 'icegatheringstatechange');
828
+ defineEventAttribute(proto, 'negotiationneeded');
829
+ defineEventAttribute(proto, 'signalingstatechange');
830
+ defineEventAttribute(proto, 'datachannel');
831
+ defineEventAttribute(proto, 'track');
832
+ defineEventAttribute(proto, 'error');