chagaif95

Untitled

Jul 3rd, 2020
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.73 KB | None | 0 0
  1. import React from 'react';
  2. import { Text, TouchableOpacity, Clipboard } from 'react-native';
  3. import { View, SafeAreaView, Button, StyleSheet } from 'react-native';
  4.  
  5. import { RTCSessionDescription, RTCPeerConnection, RTCView, mediaDevices } from 'react-native-webrtc';
  6.  
  7.  
  8. export default function App() {
  9.  
  10. // Aarenet: variables for Aareswitch
  11.  
  12. let peerConnection;
  13. let remoteAnswer
  14. let sdpVariable
  15. let cid;
  16.  
  17.  
  18. let rtcConfig = {};
  19. let sdpSent = false;
  20. let ws = new WebSocket("wss://siptest.aarenet.com:8449/anrtcp");
  21.  
  22. // Aarenet: WebSocket
  23.  
  24. ws.onopen = function (event) {
  25.  
  26. console.log("[open] Connection established");
  27. console.log("Sending to server");
  28.  
  29.  
  30. var config = {
  31. type: "register",
  32. userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36",
  33. locationParam: { "notifications": true, "audio": true, "video": true },
  34. locationHref: "https://siptest.aarenet.com:8449/webphone.jsp",
  35. isRtcUser: false,
  36. username: "aan1_cfs_demo_39",
  37. password: "Wph4cf20"
  38. };
  39.  
  40. var message = JSON.stringify(config);
  41. if (ws.readyState === 1) {
  42. console.log('wsSend: ' + message);
  43. ws.send(message);
  44. } else {
  45. console.log('failed to send message. ws state: ' + ws.readyState);
  46. }
  47.  
  48. };
  49.  
  50. ws.onmessage = function (event) {
  51.  
  52. let message = JSON.parse(event.data);
  53. if (message.type !== 'keepalive')
  54. console.log(`[message] Data received from server: ${event.data}`);
  55. if (message.type == "welcome") {
  56. rtcConfig = message.config.rtcConfig;
  57. }
  58. if (message.type == "answer") {
  59. var answer = message;
  60. if (answer.sdp.includes("m=video 0")) {
  61. var index = answer.sdp.indexOf("m=video 0");
  62. var s1 = answer.sdp.substring(0, index);
  63. var s2 = answer.sdp.substring(index);
  64. s2 = s2.replace(/(a=recvonly|a=sendonly)/, "a=inactive");
  65. answer.sdp = s1 + s2;
  66. }
  67. try {
  68. remoteAnswer = new RTCSessionDescription(answer);
  69.  
  70. } catch (error) {
  71. console.error(error);
  72. }
  73.  
  74. peerConnection.setRemoteDescription(remoteAnswer).then(
  75. peerConnection.createAnswer().then(e => {
  76. peerConnection.setLocalDescription(e).then(() => {
  77. sdpVariable = peerConnection.localDescription.sdp;
  78. window.setTimeout(() => {
  79. console.log('window.setTimeout');
  80.  
  81. let config =
  82. {
  83. "type": "answer",
  84. "cid": "s123345",
  85. "destination": "00041766524456",
  86. "sdp": sdpVariable
  87. };
  88.  
  89.  
  90. var message = JSON.stringify(config);
  91. if (ws.readyState === 1) {
  92. console.log('wsSend: ' + message);
  93. // Aarenet: making sure the offer is only sent once.
  94. if (sdpSent === false) {
  95. console.log(message);
  96. ws.send(message);
  97. // Aarenet: setting sdpSent to true so we don't send multiple calls to the Web Socket, we send this from here because
  98. // this is where we get all the ice candidates but we don't want to send an offer after every ice candidate that is registered and
  99. // we make sure all of them are registered before calling by waiting 2 seconds.
  100. sdpSent = true;
  101. // Aarenet: copying the sdp to the clipboard to analise better from the PC
  102. Clipboard.setString(sdpVariable);
  103. console.log(sdpVariable);
  104. }
  105. } else {
  106. console.log('failed to send message. ws state: ' + ws.readyState);
  107. }
  108.  
  109. }, 2000);
  110. }).catch((error) => {
  111. console.log(error);
  112. });
  113.  
  114. }).catch((error) => {
  115. console.log(error);
  116. })
  117. ).catch((error) => {
  118. console.log(error);
  119. });
  120. }
  121.  
  122.  
  123.  
  124. };
  125.  
  126. ws.onclose = function (event) {
  127.  
  128. if (event.wasClean) {
  129. console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
  130. } else {
  131. // e.g. server process killed or network down
  132. // event.code is usually 1006 in this case
  133. console.log('[close] Connection died');
  134. }
  135.  
  136. };
  137.  
  138. ws.onerror = function (error) {
  139. console.log(`[error] ${error.message}`);
  140. };
  141.  
  142. // Aarenet: code from demo app
  143.  
  144. const [localStream, setLocalStream] = React.useState();
  145. const [remoteStream, setRemoteStream] = React.useState();
  146. const [cachedLocalPC, setCachedLocalPC] = React.useState();
  147. const [cachedRemotePC, setCachedRemotePC] = React.useState();
  148.  
  149. const [isMuted, setIsMuted] = React.useState(false);
  150.  
  151. const startLocalStream = async () => {
  152. console.log('testing startLocalStream')
  153. // isFront will determine if the initial camera should face user or environment
  154. const isFront = true;
  155. const devices = await mediaDevices.enumerateDevices();
  156.  
  157. const facing = isFront ? 'front' : 'environment';
  158. const videoSourceId = devices.find(device => device.kind === 'videoinput' && device.facing === facing);
  159. const facingMode = isFront ? 'user' : 'environment';
  160. // Aarenet: changed the video to false, since we are testing audio with Aareswitch.
  161. const constraints = {
  162. audio: true,
  163. video: false, /* {
  164. mandatory: {
  165. minWidth: 500, // Provide your own width, height and frame rate here
  166. minHeight: 300,
  167. minFrameRate: 30,
  168. },
  169. facingMode,
  170. optional: videoSourceId ? [{ sourceId: videoSourceId }] : [],
  171. }, */
  172. };
  173. const newStream = await mediaDevices.getUserMedia(constraints);
  174. setLocalStream(newStream);
  175. };
  176.  
  177. // Aarenet: here is what happens when you press on the call button - a RTCPeerConnection is created.
  178. const callAareswitch = async () => {
  179.  
  180. console.log('callAareswitch');
  181.  
  182. // Aarenet: rtcConfig is set from a message with type welcome coming in to the Web Socket ws.onmessage method
  183. peerConnection = new RTCPeerConnection(rtcConfig, { optional: [{ DtlsSrtpKeyAgreement: true }] });
  184.  
  185. // Aarenet: probably not necessary to have this in a try catch block, but why not.
  186. try {
  187. peerConnection.addStream(localStream);
  188. } catch (error) {
  189. console.error(error);
  190. }
  191.  
  192. // Aarenet: this creates the sdp and when it is ready we set it to the sdpVariable.
  193. peerConnection.createOffer().then(sdp => peerConnection.setLocalDescription(sdp)).then(() => {
  194. // just to get the onicecandidates to start
  195. }).catch((error) => {
  196. console.log(error);
  197. });
  198.  
  199. // Aarenet: added a timeout so we do not miss the ice candidates coming in
  200. let count = 0;
  201. peerConnection.onicecandidate = e => {
  202. Clipboard.setString(JSON.stringify(e.candidate));
  203. console.log(JSON.stringify(e.candidate))
  204. console.log('onicecandidate');
  205. count++;
  206.  
  207. window.setTimeout(() => {
  208. console.log('window.setTimeout');
  209.  
  210. peerConnection.createOffer().then(sdp => peerConnection.setLocalDescription(sdp)).then(() => {
  211. sdpVariable = peerConnection.localDescription.sdp;
  212. let config =
  213. {
  214. "type": "offer",
  215. "cid": "s123345",
  216. "destination": "00041766524456",
  217. "sdp": sdpVariable
  218. };
  219.  
  220.  
  221. var message = JSON.stringify(config);
  222. if (ws.readyState === 1) {
  223. console.log('wsSend: ' + message);
  224. // Aarenet: making sure the offer is only sent once.
  225. if (sdpSent === false) {
  226. ws.send(message);
  227. // Aarenet: setting sdpSent to true so we don't send multiple calls to the Web Socket, we send this from here because
  228. // this is where we get all the ice candidates but we don't want to send an offer after every ice candidate that is registered and
  229. // we make sure all of them are registered before calling by waiting 1 second.
  230. sdpSent = true;
  231. // Aarenet: copying the sdp to the clipboard to analyze better from the PC
  232. Clipboard.setString(sdpVariable);
  233. console.log(sdpVariable);
  234. console.log(count);
  235. }
  236. } else {
  237. console.log('failed to send message. ws state: ' + ws.readyState);
  238. }
  239. }).catch((error) => {
  240. console.log(error);
  241. });
  242.  
  243.  
  244.  
  245. }, 1000);
  246. };
  247.  
  248. /* // Aarenet: not sure what this does but it was in the demo app in the call section so it might be necessary.
  249. setCachedLocalPC(peerConnection);
  250. */
  251.  
  252.  
  253. peerConnection.onaddstream = e => { console.log(e.message) };
  254. peerConnection.onremovestream = e => { console.log(e.message) };
  255. peerConnection.onnegotiationneeded = e => {
  256. /* peerConnection.createOffer().then(sdp => peerConnection.setLocalDescription(sdp)).then(() => {
  257.  
  258. console.log(peerConnection.localDescription.sdp);
  259. let config =
  260. {
  261. "type": "offer",
  262. "cid": "s123345",
  263. "destination": "00041766524456",
  264. "sdp": peerConnection.localDescription.sdp
  265. };
  266.  
  267.  
  268. var message = JSON.stringify(config);
  269. ws.send(message);
  270. }).catch((error) => {
  271. console.log(error);
  272. }); */
  273. // console.log(e.constructor.name); // RTCEvent
  274. };
  275.  
  276.  
  277.  
  278. /*peerConnection.onconnectionstatechange = e => { console.log(e.message) };
  279. peerConnection.oniceconnectionstatechange = e => { console.log(e.message) };
  280. peerConnection.onicegatheringstatechange = e => { console.log(e.message) };
  281. peerConnection.onsignalingstatechange = e => { console.log(e.message) };
  282. peerConnection.ontrack = e => { console.log(e.message) }; */
  283.  
  284.  
  285. }
  286.  
  287. const startCall = async () => {
  288.  
  289. console.log('testing startCall')
  290.  
  291.  
  292. // You'll most likely need to use a STUN server at least. Look into TURN and decide if that's necessary for your project
  293. const configuration = { iceServers: [{ url: 'stun:stun.l.google.com:19302' }] };
  294. const localPC = new RTCPeerConnection(configuration);
  295. const remotePC = new RTCPeerConnection(configuration);
  296.  
  297. // could also use "addEventListener" for these callbacks, but you'd need to handle removing them as well
  298. localPC.onicecandidate = e => {
  299. try {
  300. console.log('localPC icecandidate:', e.candidate);
  301. if (e.candidate) {
  302. remotePC.addIceCandidate(e.candidate);
  303. }
  304. } catch (err) {
  305. console.error(`Error adding remotePC iceCandidate: ${err}`);
  306. }
  307. };
  308. remotePC.onicecandidate = e => {
  309. try {
  310. console.log('remotePC icecandidate:', e.candidate);
  311. if (e.candidate) {
  312. localPC.addIceCandidate(e.candidate);
  313. }
  314. } catch (err) {
  315. console.error(`Error adding localPC iceCandidate: ${err}`);
  316. }
  317. };
  318. remotePC.onaddstream = e => {
  319. console.log('remotePC tracking with ', e);
  320. if (e.stream && remoteStream !== e.stream) {
  321. console.log('RemotePC received the stream', e.stream);
  322. setRemoteStream(e.stream);
  323. }
  324. };
  325.  
  326. // AddTrack not supported yet, so have to use old school addStream instead
  327. // newStream.getTracks().forEach(track => localPC.addTrack(track, newStream));
  328. localPC.addStream(localStream);
  329. try {
  330. const offer = await localPC.createOffer();
  331. console.log('Offer from localPC, setLocalDescription');
  332. await localPC.setLocalDescription(offer);
  333. console.log('remotePC, setRemoteDescription');
  334. console.log(localPC.localDescription.sdp)
  335. Clipboard.setString(localPC.localDescription.sdp);
  336. await remotePC.setRemoteDescription(localPC.localDescription);
  337. console.log('RemotePC, createAnswer');
  338. const answer = await remotePC.createAnswer();
  339. console.log(`Answer from remotePC: ${answer.sdp}`);
  340. console.log('remotePC, setLocalDescription');
  341. await remotePC.setLocalDescription(answer);
  342. console.log('localPC, setRemoteDescription');
  343. await localPC.setRemoteDescription(remotePC.localDescription);
  344. } catch (err) {
  345. console.error(err);
  346. }
  347. setCachedLocalPC(localPC);
  348. setCachedRemotePC(remotePC);
  349. };
  350.  
  351. const switchCamera = () => {
  352. localStream.getVideoTracks().forEach(track => track._switchCamera());
  353. };
  354.  
  355. // Mutes the local's outgoing audio
  356. const toggleMute = () => {
  357. if (!remoteStream) return;
  358. localStream.getAudioTracks().forEach(track => {
  359. console.log(track.enabled ? 'muting' : 'unmuting', ' local track', track);
  360. track.enabled = !track.enabled;
  361. setIsMuted(!track.enabled);
  362. });
  363. };
  364.  
  365. const closeStreams = () => {
  366. if (cachedLocalPC) {
  367. cachedLocalPC.removeStream(localStream);
  368. cachedLocalPC.close();
  369. }
  370. if (cachedRemotePC) {
  371. cachedRemotePC.removeStream(remoteStream);
  372. cachedRemotePC.close();
  373. }
  374. setLocalStream();
  375. setRemoteStream();
  376. setCachedRemotePC();
  377. setCachedLocalPC();
  378. };
  379.  
  380. // Aarenet: added this line '<Button title="Call" onPress={callAareswitch} />' so that we have a button we can call from
  381. // it calls the callAareswitch funtion every time you press it.
  382.  
  383. return (
  384. <SafeAreaView style={styles.container}>
  385. <Button title="Call" onPress={callAareswitch} />
  386. {!localStream && <Button title="Click to start stream" onPress={startLocalStream} />}
  387. {localStream && <Button title="Click to start call" onPress={startCall} disabled={!!remoteStream} />}
  388.  
  389. {(
  390. <View style={styles.toggleButtons}>
  391. <Button title="Switch camera" onPress={switchCamera} />
  392. <Button title={`${isMuted ? 'Unmute' : 'Mute'} stream`} onPress={toggleMute} disabled={!remoteStream} />
  393. </View>
  394. )}
  395.  
  396. <View style={styles.rtcview}>
  397. {localStream && <RTCView style={styles.rtc} streamURL={localStream.toURL()} />}
  398. </View>
  399. <View style={styles.rtcview}>
  400. {remoteStream && <RTCView style={styles.rtc} streamURL={remoteStream.toURL()} />}
  401. </View>
  402. <Button title="Click to stop call" onPress={closeStreams} disabled={!remoteStream} />
  403. </SafeAreaView>
  404. );
  405. }
  406.  
  407. const styles = StyleSheet.create({
  408. container: {
  409. backgroundColor: '#313131',
  410. justifyContent: 'space-between',
  411. alignItems: 'center',
  412. height: '100%',
  413. },
  414. text: {
  415. fontSize: 30,
  416. },
  417. rtcview: {
  418. justifyContent: 'center',
  419. alignItems: 'center',
  420. height: '40%',
  421. width: '80%',
  422. backgroundColor: 'black',
  423. },
  424. rtc: {
  425. width: '80%',
  426. height: '100%',
  427. },
  428. toggleButtons: {
  429. width: '100%',
  430. flexDirection: 'row',
  431. justifyContent: 'space-around',
  432. },
  433. });
Advertisement
Add Comment
Please, Sign In to add comment