@fctv/js
Version:
Call SDK for JavaScript
262 lines (229 loc) • 6.62 kB
JavaScript
import { UserSession, UserSessionEvent, CallState } from '@fctv/js';
import { ConnectionStatus, UserStatus } from './constants';
import {
LOGIN,
LOGOUT,
UPDATE_CONNECTION_STATUS,
UPDATE_USER_STATUS,
NEW_CALL,
TIME_ELAPSED,
REMOTE_STREAM,
LOCAL_STREAM,
UPDATE_CALL_STATE
} from './actions/actionTypes'
import store from '../store';
let _fcTVServiceInstance = null;
const _savedLoggedInUserKey = '_savedLoggedInUserKey';
export default class FCTVService {
_timer = null;
static getInstance = () => {
if (!_fcTVServiceInstance) {
_fcTVServiceInstance = new FCTVService();
}
return _fcTVServiceInstance;
};
get isLoggedIn() {
return this.client && this.client.isLoggedIn;
}
constructor() {
this.activeCall = null;
this._setActiveCall = this._setActiveCall.bind(this);
this._startTimer = this._startTimer.bind(this);
this._stopTimer = this._stopTimer.bind(this);
// Get logged user from local storage
const savedLoggedInUser = localStorage.getItem(_savedLoggedInUserKey);
if (savedLoggedInUser) {
this.user = JSON.parse(savedLoggedInUser);
}
}
login(options) {
this.logout(true); // Close the old if existing, but keep the session
this.client = new UserSession(options);
this.user = options;
this._subscribeEvents();
this.client.connect();
store.dispatch({
type: UPDATE_CONNECTION_STATUS,
payload: {
connectionStatus: ConnectionStatus.CONNECTING
}
})
}
logout(keepSession = false) {
this.client && this.client.close(keepSession);
// Remove saved user from localStorage
localStorage.removeItem(_savedLoggedInUserKey);
this.user = null;
this._stopTimer();
}
_subscribeEvents() {
this.client.on(UserSessionEvent.ON_READY, () => {
console.log('[FCTVService] Ready');
store.dispatch({
type: UPDATE_CONNECTION_STATUS,
payload: {
connectionStatus: ConnectionStatus.READY
}
})
});
this.client.on(UserSessionEvent.ON_CLOSED, () => {
console.log('[FCTVService] Closed');
store.dispatch({
type: LOGOUT
});
});
this.client.on(UserSessionEvent.ON_ERROR, (err, data) => {
console.log('[FCTVService] Error', err);
store.dispatch({
type: UPDATE_CONNECTION_STATUS,
payload: {
connectionStatus: ConnectionStatus.ERROR
}
})
});
this.client.on(UserSessionEvent.ON_RETRYING, (err, data) => {
console.log('[FCTVService] Retrying');
store.dispatch({
type: UPDATE_CONNECTION_STATUS,
payload: {
connectionStatus: ConnectionStatus.RETRYING
}
})
});
this.client.on(UserSessionEvent.ON_LOGIN_ERROR, (err, data) => {
console.log('[FCTVService] Login Error');
store.dispatch({
type: UPDATE_USER_STATUS,
payload: {
userStatus: UserStatus.LOGIN_FAILED
}
})
});
this.client.on(UserSessionEvent.ON_LOGIN_SUCCESS, (err, data) => {
console.log('[FCTVService] Login Success', data);
// Save to localStorage
localStorage.setItem(_savedLoggedInUserKey, JSON.stringify(this.user));
store.dispatch({
type: LOGIN,
payload: {
user: this.user
}
})
});
this.client.on(UserSessionEvent.ON_SPEED_CHANGE, (err, data) => {
console.log('[FCTVService] Speed change', data);
});
this.client.on(UserSessionEvent.ON_USER_MEDIA_ERROR, (err) => {
console.error('[FCTVService] User Media', err);
});
this.client.on(UserSessionEvent.ON_USER_PEER_ERROR, (err) => {
console.error('[FCTVService] User Peer', err);
});
this.client.on(UserSessionEvent.ON_INCOMING_CALL, (err, call) => {
console.log('[FCTVService] Incoming call', call);
let t = setTimeout(() => {
this.answerCall(call);
clearTimeout(t);
}, 5000);
});
this.client.on(UserSessionEvent.ON_RECOVERY_CALL, (err, call) => {
console.debug('[FCTVService] Call need recovery', call);
let t = setTimeout(() => {
this.answerCall(call);
clearTimeout(t);
}, 5000);
});
this.client.on(UserSessionEvent.ON_CALL_LOCAL_STREAM, (err, call) => {
console.debug('[FCTVService] Call local stream', call);
store.dispatch({
type: LOCAL_STREAM,
payload: {
localStream: call.localStream
}
})
});
this.client.on(UserSessionEvent.ON_CALL_REMOTE_STREAM, (err, call) => {
console.debug('[FCTVService] Call remote stream', call);
store.dispatch({
type: REMOTE_STREAM,
payload: {
remoteStream: call.remoteStream
}
})
});
this.client.on(UserSessionEvent.ON_CALL_STATE_UPDATE, (err, call) => {
console.debug('[App] Call state', call.state);
if (this.activeCall && this.activeCall.id === call.id) {
store.dispatch({
type: UPDATE_CALL_STATE,
payload: {
callState: call.state
}
})
}
switch (call.state) {
case CallState.TRYING:
this._setActiveCall(call);
break;
case CallState.RINGING:
break;
case CallState.ACTIVE:
this._setActiveCall(call);
this._startTimer();
break;
case CallState.DESTROYED:
if (this.activeCall && this.activeCall.id === call.id) {
this._setActiveCall(null);
this._stopTimer();
}
break;
default:
break;
}
});
}
_setActiveCall(call) {
this.activeCall = call;
store.dispatch({
type: NEW_CALL,
payload: {
call: call
}
})
}
makeCall(destinationNumber) {
const data = {
destinationNumber
};
this.hangupCall();
this.activeCall = this.client.newCall(data);
}
hangupCall() {
if (this.activeCall) {
this.activeCall.hangup()
}
}
answerCall(call) {
// Hangup the old call
if (this.activeCall && call.id !== this.activeCall.id) {
this.hangupCall();
}
call.answer();
}
_startTimer() {
this._timer = setInterval(()=> {
if (this.activeCall) {
const elapsedSeconds = Math.round((Date.now() - this.activeCall.activeTime)/1000);
store.dispatch({
type: TIME_ELAPSED,
payload: {
timeElapsed: elapsedSeconds
}
})
}
}, 1000);
}
_stopTimer() {
this._timer && clearInterval(this._timer);
}
}