hub-video-tester/src/App.js

479 lines
14 KiB
JavaScript

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 (
<div className='App'>
<h1>WebRTC DEV Client 0.3</h1>
<br></br>
<h2>
<u>STUN and TURN servers</u>
</h2>
STUN Server URL :
<input
placeholder='ex: stun:stun.services.mozilla.com:3478'
onChange={this.handleChangeStunUrl}
value={stunUrl}
style={{ margin: 10, width: 250 }}
/>
<br></br>
TURN Server URL :
<input
placeholder='ex: turn:numb.viagenie.ca:3478'
onChange={this.handleChangeTurnUrl}
value={turnUrl}
style={{ margin: 10, width: 250 }}
/>
<br></br>
TURN Server Username :
<input
placeholder='ex: gigel'
onChange={this.handleChangeTurnUsername}
value={turnUsername}
style={{ margin: 10, width: 250 }}
/>
<br></br>
TURN Server Credential :
<input
placeholder='ex: superGiGi'
onChange={this.handleChangeTurnCredential}
value={turnCredential}
style={{ margin: 10, width: 250 }}
/>
<br></br>
<br></br>
<h2>
<u>Login</u>
</h2>
Username :
<input
placeholder='user'
onChange={this.handleChangeLogin}
value={login}
style={{ margin: 10, width: 250 }}
/>
<br></br>
Password :
<input
placeholder='password'
onChange={this.handleChangePassword}
value={password}
style={{ margin: 10, width: 250 }}
/>
<br></br>
<button
onClick={this.handleLoginClick}
style={{ margin: 10, width: 100 }}
>
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 && 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;