hub-video-tester/src/App.js

313 lines
11 KiB
JavaScript

import React, { Component } from 'react'
import './App.css';
const io = require("socket.io-client");
let localStream = null;
let remoteStream = null;
const iceServer = {
'iceServer': [
// { 'urls': 'stun:stun.services.mozilla.com' }, // public
// { 'urls': 'stun:stun.l.google.com:19302' } // public
{ 'urls': 'dev.linx.safemobile.com:19302' }
]
}
let localVideo = document.getElementById("localVideo");
let remoteVideo = document.getElementById("remoteVideo");
const streamConstraints = {
audio: false,
video: true
};
class App extends Component {
constructor() {
super();
this.state = {
login: '',
password: '',
user: null,
hubStatus: 0, // 0 uninitialized | 1 connecting | 2 connected | 3 connection error
socket: null,
arsSent: false,
dest_asset_id: '',
isCaller: false,
callId: null,
rtcPeerConnection: null
};
}
componentDidMount() {
}
handleLoginClick = async () => {
const loginRequest = await fetch('http://localhost:41418/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("ws://localhost:41414", {reconnect:true, transports: ['websocket']}) }, () => {
const socket = this.state.socket;
socket.on('connect', () => {
this.setState({ hubStatus: 2 })
// Send ARS after connected to HUB
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
socket.on('video', (data) => {
const parseDate = JSON.parse(data);
console.log('video', parseDate);
// The response to the 'notify-request' (hardcoded 'YES')
if(parseDate.type === 'notify-request') {
this.setState({ dest_asset_id: parseInt(parseDate.origin_asset_id), callId: parseInt(parseDate.video_call_id) });
socket.emit('video', JSON.stringify({
origin_asset_id: this.state.user.asset.id,
dest_asset_id: parseInt(parseDate.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.name,
video_call_id: parseDate.video_call_id,
answer: 'YES'
}));
}
// Handler for 'notify-end'(when the video closed)
if(parseDate.type === 'notify-end') {
console.log('notify-end');
this.cleanVideoStreams();
}
// Handler for 'notify-answer'
if(parseDate.type === 'notify-answer') {
// Create media stream
navigator.mediaDevices.getUserMedia(streamConstraints).then(stream => {
console.log('Created getUserMedia', stream);
localStream = stream;
localVideo.srcObject = stream;
// Create SDP
this.setState({ rtcPeerConnection: new RTCPeerConnection(iceServer) }, () => {
this.state.rtcPeerConnection.onicecandidate = this.onIceCandidate;
this.state.rtcPeerConnection.ontrack = this.onAddStream;
this.state.rtcPeerConnection.addTrack(localStream.getTracks()[0], localStream); // video
// rtcPeerConnection.addTrack(localStream.getTracks()[1], localStream) // audio
// Create a offer
this.state.rtcPeerConnection.createOffer().then(sessionDescription => {
// Save SDP in state and send it to destination asset_id as offer
this.setState({ isCaller: true, callId: parseInt(parseDate.video_call_id) }, () => {
this.state.rtcPeerConnection.setLocalDescription(sessionDescription);
console.log('Created SDP', sessionDescription);
socket.emit('video', JSON.stringify({
origin_asset_id: this.state.user.asset.id,
type: 'offer',
sdp: sessionDescription,
dest_asset_id: parseInt(this.state.dest_asset_id),
video_call_id: parseDate.video_call_id
}));
})
})
.catch(e => { console.log(e); })
})
})
.catch(err => {
console.log('An error occured', err);
})
}
// Handler for 'offer'
if(parseDate.type === 'offer') {
// When we are NOT the caller
if(!this.state.isCaller) {
// Create media stream
navigator.mediaDevices.getUserMedia(streamConstraints).then(stream => {
console.log('Created getUserMedia', stream);
localStream = stream;
localVideo.srcObject = stream;
// Create SDP
this.setState({ rtcPeerConnection: new RTCPeerConnection(iceServer) }, () => {
this.state.rtcPeerConnection.onicecandidate = this.onIceCandidate;
this.state.rtcPeerConnection.ontrack = this.onAddStream;
this.state.rtcPeerConnection.addTrack(localStream.getTracks()[0], localStream); // video
// rtcPeerConnection.addTrack(localStream.getTracks()[1], localStream) // audio
// Set setRemoteDescription to be sender SDP
this.state.rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(parseDate.sdp));
// Create an answer
this.state.rtcPeerConnection.createAnswer().then(sessionDescription => {
// Save SDP in state and send it to destination asset_id as offer
this.setState({ sdp: sessionDescription }, () => {
this.state.rtcPeerConnection.setLocalDescription(sessionDescription);
console.log('Created SDP', sessionDescription);
socket.emit('video', JSON.stringify({
origin_asset_id: this.state.user.asset.id,
type: 'offer',
sdp: sessionDescription,
dest_asset_id: parseInt(this.state.dest_asset_id),
video_call_id: parseDate.video_call_id
}));
})
})
.catch(e => { console.log(e); })
})
})
} else {
// When we ARE the caller
console.log('parseDate.sdp', parseDate.sdp);
this.state.rtcPeerConnection.setRemoteDescription(new RTCSessionDescription(parseDate.sdp));
}
}
if(parseDate.type === 'candidate') {
const candidate = new RTCIceCandidate({
sdpMLineIndex: parseDate.label,
candidate: parseDate.candidate
});
this.state.rtcPeerConnection.addIceCandidate(candidate);
}
});
});
})
}
onAddStream = (event) => {
console.log('onAddStream', event);
remoteVideo.srcObject = event.streams[0];
remoteStream = event.streams[0];
}
onIceCandidate = (event) => {
if(event.candidate) {
console.log('sending ice candidate', event.candidate);
this.state.socket.emit('video', JSON.stringify({
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate,
dest_asset_id: this.state.dest_asset_id
}));
}
}
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});
}
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: null
}));
}
closeVideo = () => {
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 = () => {
this.state.rtcPeerConnection.close();
this.setState({ callId: null, rtcPeerConnection: null });
localVideo.srcObject = null;
remoteVideo.srcObject = null;
}
render() {
const { login, password, user, hubStatus, arsSent, dest_asset_id, isCaller, callId } = { ...this.state };
return (
<div className="App">
<h1>HUB TESTER</h1>
<input
placeholder='user'
onChange={this.handleChangeLogin}
value={login}
/>
<input
placeholder='password'
onChange={this.handleChangePassword}
value={password}
/>
<button onClick={this.handleLoginClick}>LOGIN</button>
<br></br>
<h2><u>isCaller:</u> {isCaller ? 'TRUE' : 'FALSE'}</h2>
<h2><u>User details:</u></h2>
{
user && (
<React.Fragment>
<h4>account_id: {user.account.id}</h4>
<h4>user_id: {user.id}</h4>
<h4>asset_id: {user.asset.id}</h4>
<h4>user_role: {user.user_role.name}</h4>
</React.Fragment>
)
}
<h2>
<u>HUB</u>
</h2>
<h4>status: {(hubStatus === 0 ? 'uninitialized' : hubStatus === 1 ? 'connecting' : hubStatus === 2 ? 'connected' : 'connection error' )}</h4>
<h4>ARS Sent: {arsSent === true ? 'TRUE' : 'FALSE'}</h4>
<h4>Call id: {callId}</h4>
<br></br>
<input
placeholder='destination_asset_id'
onChange={this.handleChangeDestAssetId}
value={dest_asset_id}
/>
<button onClick={this.handleClickEvent} disabled={dest_asset_id.length === 0 ? true : false}>Send `video` notify-request</button>
<br></br>
<button onClick={this.closeVideo} style={{ margin: 40}} disabled={callId !== null ? false : true}>Close Video</button>
</div>
);
};
};
export default App;