import React, { Component } from 'react'; import './App.css'; const io = require('socket.io-client'); let stream, pc; let localStream; // let remoteStream; let localVideo = document.getElementById('localVideo'); let remoteVideo = document.getElementById('remoteVideo'); class App extends Component { constructor() { super(); this.state = { login: 'lx-adi', password: 'Safemobile123', user: null, hubStatus: 0, // 0 uninitialized | 1 connecting | 2 connected | 3 connection error socket: null, arsSent: false, dest_asset_id: '1', isCaller: false, callId: null, stunUrl: 'stun:18.197.242.79:3478', turnUrl: 'turn:18.197.242.79:3478', turnUsername: 'sergiu', turnCredential: 'test123', }; } componentDidMount = async () => { console.log('🟢 START'); stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false, }); localStream = stream; localVideo.srcObject = stream; }; onAddStream = (event) => { console.log('onAddStream', event); remoteVideo.srcObject = event.streams[0]; // remoteStream = event.streams[0]; }; videoConfig = () => { return { iceServers: [ { urls: [this.state.stunUrl], }, { username: this.state.turnUsername, credential: this.state.turnCredential, urls: [this.state.turnUrl], }, ], rtcpMuxPolicy: 'negotiate', }; }; handleLoginClick = async () => { const loginRequest = await fetch( 'https://dev.linx.safemobile.com/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ login: this.state.login, password: this.state.password, }), } ); const loginResponseJson = await loginRequest.json(); this.setState({ user: loginResponseJson.data }, () => { // Connect to HUB this.setState( { socket: io('https://hub.dev.linx.safemobile.com/', { reconnect: true, transports: ['websocket'], }), }, () => { this.state.socket.on('connect', () => { this.setState({ hubStatus: 2 }); // Send ARS after connected to HUB this.state.socket.emit( 'ars', JSON.stringify({ ars: true, asset_id: this.state.user.asset.id, account_id: this.state.user.account.id, }) ); this.setState({ arsSent: true }); }); // HUB 'video' event handler this.state.socket.on('video', async (data) => { const parseData = JSON.parse(data); console.log('[VIDEO]', parseData); if (parseData.type === 'notify-request') { console.log('NOTIFY-REQUEST'); pc = new RTCPeerConnection(this.videoConfig()); pc.ontrack = this.onAddStream; pc.addTrack(localStream.getTracks()[0], localStream); // pc.addTrack(localStream.getTracks()[1], localStream) pc.oniceconnectionstatechange = this.onIceConnectionStateChange; pc.onsignalingstatechange = this.onSignalingStateChange; await pc.setLocalDescription(await pc.createOffer()); this.state.socket.emit( 'video', JSON.stringify({ origin_asset_id: this.state.user.asset.id, dest_asset_id: parseInt(parseData.origin_asset_id), type: 'notify-answer', origin_asset_priority: this.state.user.asset.priority, origin_asset_type_name: this.state.user.user_role.name, origin_asset_name: this.state.user.asset.name, video_call_id: parseInt(parseData.video_call_id), answer: 'accepted', // answer: 'rejected' sdp: pc.localDescription, }) ); this.setState({ callId: parseInt(parseData.video_call_id), dest_asset_id: parseInt(parseData.origin_asset_id), }); } if (parseData.type === 'notify-answer') { pc = new RTCPeerConnection(this.videoConfig()); pc.ontrack = this.onAddStream; pc.addTrack(localStream.getTracks()[0], localStream); // pc.addTrack(localStream.getTracks()[1], localStream) pc.oniceconnectionstatechange = this.onIceConnectionStateChange; pc.onsignalingstatechange = this.onSignalingStateChange; console.log('NOTIFY-ANSWER'); this.setState({ callId: parseInt(parseData.video_call_id) }); this.offerReceived(parseData); } else if (parseData.type === 'offer') { if (parseData.sdp.type === 'offer') { console.log('[OFFER]'); this.setState({ callId: parseInt(parseData.video_call_id) }); this.offerReceived(parseData); } else if (parseData.sdp.type === 'answer') { console.log('[ANSWER]'); await pc.setRemoteDescription(parseData.sdp); pc.onicecandidate = ({ candidate }) => { console.log('candidate1', candidate); this.state.socket.emit( 'video', JSON.stringify({ type: 'candidate', candidate, dest_asset_id: parseInt(this.state.dest_asset_id), video_call_id: parseData.video_call_id, }) ); }; this.state.socket.emit( 'video', JSON.stringify({ origin_asset_id: this.state.user.asset.id, dest_asset_id: parseInt(this.state.dest_asset_id), type: 'offer', origin_asset_priority: this.state.user.asset.priority, origin_asset_type_name: this.state.user.user_role.name, origin_asset_name: this.state.user.asset.name, video_call_id: this.state.callId, sdp: pc.localDescription, }) ); } } else if (parseData.type === 'candidate') { console.log('candidate parseData', parseData); if (parseData.candidate) { console.log('parseData.candidate', parseData.candidate); pc.addIceCandidate(parseData.candidate).catch((e) => { console.log(e); }); } } else if (parseData.type === 'notify-end') { this.cleanVideoStreams(); } else if (parseData.type === 'retry') { if (parseData.description === 'sdp') { await pc.setLocalDescription(await pc.createOffer()); this.state.socket.emit( 'video', JSON.stringify({ origin_asset_id: this.state.user.asset.id, dest_asset_id: parseInt(this.state.dest_asset_id), video_call_id: this.state.callId, type: 'retry', description: 'sdp', sdp: pc.localDescription, }) ); } } }); } ); }); }; offerReceived = async (offer) => { console.log('------- offerReceived -------', offer); await pc.setLocalDescription(await pc.createAnswer()); await pc.setRemoteDescription(offer.sdp); pc.onicecandidate = ({ candidate }) => { this.state.socket.emit( 'video', JSON.stringify({ type: 'candidate', candidate: candidate, dest_asset_id: parseInt(this.state.dest_asset_id), video_call_id: this.state.callId, }) ); }; pc.onnegotiationneeded = async () => { console.log('--------- onnegotiationneeded START --------'); try { console.log('IIIIIIIIIIIIIIIIIIIIIIIII3', this.state.callId); await pc.setLocalDescription(await pc.createOffer()); this.state.socket.emit( 'video', JSON.stringify({ origin_asset_id: this.state.user.asset.id, dest_asset_id: parseInt(this.state.dest_asset_id), type: 'offer', origin_asset_priority: this.state.user.asset.priority, origin_asset_type_name: this.state.user.user_role.name, origin_asset_name: this.state.user.asset.name, video_call_id: this.state.callId, sdp: pc.localDescription, }) ); } catch (err) { console.error(err); } }; this.state.socket.emit( 'video', JSON.stringify({ origin_asset_id: this.state.user.asset.id, dest_asset_id: parseInt(this.state.dest_asset_id), type: 'offer', origin_asset_priority: this.state.user.asset.priority, origin_asset_type_name: this.state.user.user_role.name, origin_asset_name: this.state.user.asset.name, video_call_id: this.state.callId, sdp: pc.localDescription, }) ); console.log('--------- onnegotiationneeded END --------'); }; handleChangeLogin = (e) => { this.setState({ login: e.target.value }); }; handleChangePassword = (e) => { this.setState({ password: e.target.value }); }; handleChangeDestAssetId = (e) => { this.setState({ dest_asset_id: e.target.value }); }; handleChangeStunUrl = (e) => { this.setState({ stunUrl: e.target.value }); }; handleChangeTurnUrl = (e) => { this.setState({ turnUrl: e.target.value }); }; handleChangeTurnUsername = (e) => { this.setState({ turnUsername: e.target.value }); }; handleChangeTurnCredential = (e) => { this.setState({ turnCredential: e.target.value }); }; handleClickEvent = () => { this.state.socket.emit( 'video', JSON.stringify({ origin_asset_id: this.state.user.asset.id, dest_asset_id: parseInt(this.state.dest_asset_id), type: 'notify-request', origin_asset_priority: this.state.user.asset.priority, origin_asset_type_name: this.state.user.user_role.name, origin_asset_name: this.state.user.name, video_call_id: this.state.callId, }) ); }; closeVideo = () => { console.log('----- closeVideo -----', this.state.callId); this.state.socket.emit( 'video', JSON.stringify({ origin_asset_id: this.state.user.asset.id, dest_asset_id: parseInt(this.state.dest_asset_id), type: 'notify-end', video_call_id: this.state.callId, }) ); this.cleanVideoStreams(); }; cleanVideoStreams = () => { console.log('------ cleanVideoStreams ------'); this.setState({ dest_asset_id: '', callId: null }); pc.close(); localVideo.srcObject = null; // remoteVideo.srcObject = null; }; render() { const { login, password, user, hubStatus, arsSent, dest_asset_id, isCaller, callId, stunUrl, turnUrl, turnUsername, turnCredential, } = { ...this.state }; return (

WebRTC DEV Client 0.3



STUN and TURN servers

STUN Server URL :

TURN Server URL :

TURN Server Username :

TURN Server Credential :



Login

Username :

Password :



isCaller: {isCaller ? 'TRUE' : 'FALSE'}

User details:

{user && (

account_id: {user.account.id}

user_id: {user.id}

asset_id: {user.asset.id}

user_role: {user.user_role.name}

)}

HUB

status:{' '} {hubStatus === 0 ? 'uninitialized' : hubStatus === 1 ? 'connecting' : hubStatus === 2 ? 'connected' : 'connection error'}

ARS Sent: {arsSent === true ? 'TRUE' : 'FALSE'}

Call id: {callId && callId}





); } } export default App;