UNPKG

infobip-rtc

Version:

Infobip RTC JavaScript SDK - Infobip WebRTC API Implementation

249 lines 12.4 kB
import events from "events"; import { InfobipGatewayImpl } from "./gateway/InfobipGateway"; import Status, { StatusLabels } from "./gateway/Status"; import { DefaultLogger } from "./log/impl/DefaultLogger"; import { DefaultDevice } from "./device/DefaultDevice"; import jwtDecode from "jwt-decode"; import * as log from "loglevel"; import { LoggerOptions } from "./log/LoggerOptions"; import { DefaultIncomingApplicationCall } from "./call/impl/DefaultIncomingApplicationCall"; import { DefaultOutgoingApplicationCall } from "./call/impl/DefaultOutgoingApplicationCall"; import { IncomingApplicationCallEvent } from "./call/event/IncomingApplicationCallEvent"; import { ApiEventEmitter } from "./util/ApiEventEmitter"; import { DefaultRoomCall } from "./call/impl/DefaultRoomCall"; import { FlowType } from "./call/FlowType"; import { PhoneCallOptions } from "./call/options/PhoneCallOptions"; import { DefaultOutgoingPhoneCall } from "./call/impl/DefaultOutgoingPhoneCall"; import { ApplicationErrorCode } from "./call/ApplicationErrorCode"; import { DefaultOutgoingWebrtcCall } from "./call/impl/DefaultOutgoingWebrtcCall"; import { WebrtcCallOptions } from "./call/options/WebrtcCallOptions"; import { ViberCallOptions } from "./call/options/ViberCallOptions"; import { DefaultOutgoingViberCall } from "./call/impl/DefaultOutgoingViberCall"; import { DefaultIncomingWebrtcCall } from "./call/impl/DefaultIncomingWebrtcCall"; import { IncomingWebrtcCallEvent } from "./call/event/IncomingWebrtcCallEvent"; import { RoomCallOptions } from "./call/options/RoomCallOptions"; import { Properties } from "./Properties"; import { ApplicationCallOptions } from "./call/options/ApplicationCallOptions"; import { User } from "./call/User"; import { InfobipRTCEvent } from "./event/InfobipRTCEvents"; import ValidationUtil from "./call/impl/util/ValidationUtil"; import { WsErrorLogger } from "./util/WsErrorLogger"; export class DefaultInfobipRTC { constructor(token, rtcOptions = {}) { this.token = token; this.rtcOptions = rtcOptions; if (!this.isWebRTCSupported()) { throw new Error('Browser does not support WebRTC.'); } rtcOptions.debug ? log.enableAll() : log.setLevel(log.levels.ERROR); this.eventEmitter = new events.EventEmitter(); this.apiEventEmitter = new ApiEventEmitter(); this.logger = new DefaultLogger(token, new LoggerOptions(), this.rtcOptions.statsUrl, this.rtcOptions.headersProvider); this.currentUser = this.getUserFromToken(jwtDecode(this.token)); this.gateway = new InfobipGatewayImpl(this.eventEmitter, this.logger, this.token); this.device = new DefaultDevice(this.logger); this.rtcConfig = rtcOptions.iceTransportPolicy === "relay" ? { iceTransportPolicy: "relay" } : {}; this.logger.setWsErrorLogger(new WsErrorLogger(this.gateway.send.bind(this.gateway))); } connect() { this.validateStatus(Status.OFFLINE, 'connect'); this.configureEventHandlers.call(this); this.gateway.connect(false); } disconnect() { if (this.logger) { this.logger.stop(); } this.gateway.disconnect(); } connectedUser() { return this.currentUser; } on(name, handler) { if (!Object.values(InfobipRTCEvent) .find(apiEvent => apiEvent === name)) { throw new Error(`Unknown event: ${name}!`); } this.apiEventEmitter.on(name, handler); } callApplication(callsConfigurationId, options) { this.validateCallsConfigurationId(callsConfigurationId); this.validateStatus(Status.CONNECTED, 'callApplication'); this.checkIfAnythingIsActive(); if (options === null || options === void 0 ? void 0 : options.customData) { ValidationUtil.validateCustomData(options.customData); } options !== null && options !== void 0 ? options : (options = ApplicationCallOptions.builder().build()); let call = new DefaultOutgoingApplicationCall(this.eventEmitter, this.gateway, this.logger, this.rtcConfig, this.device, callsConfigurationId, options, this.currentUser.identity, this.token, this.apiUrl); this.callActive = true; return call; } callWebrtc(identity, options) { if (!DefaultInfobipRTC.IDENTITY_PATTERN.test(identity)) { throw Error("Invalid destination."); } options !== null && options !== void 0 ? options : (options = WebrtcCallOptions.builder().build()); return new DefaultOutgoingWebrtcCall(this, options, this.currentUser.identity, identity); } callPhone(phoneNumber, phoneCallOptions) { if (!DefaultInfobipRTC.PHONE_NUMBER_PATTERN.test(phoneNumber)) { throw new Error("Invalid destination"); } phoneCallOptions !== null && phoneCallOptions !== void 0 ? phoneCallOptions : (phoneCallOptions = PhoneCallOptions.builder().build()); return new DefaultOutgoingPhoneCall(this, phoneCallOptions, this.currentUser.identity, phoneNumber); } callViber(phoneNumber, from, viberCallOptions) { if (!DefaultInfobipRTC.PHONE_NUMBER_PATTERN.test(phoneNumber)) { throw new Error("Invalid destination"); } if (!DefaultInfobipRTC.PHONE_NUMBER_PATTERN.test(from)) { throw Error("Invalid caller identifier."); } viberCallOptions !== null && viberCallOptions !== void 0 ? viberCallOptions : (viberCallOptions = ViberCallOptions.builder().build()); return new DefaultOutgoingViberCall(this, viberCallOptions, this.currentUser.identity, phoneNumber, from); } joinRoom(roomName, options) { if (!roomName || !DefaultInfobipRTC.CONFERENCE_ID_PATTERN.test(roomName)) { throw Error("Invalid room name."); } options !== null && options !== void 0 ? options : (options = RoomCallOptions.builder().build()); return new DefaultRoomCall(this, options, roomName); } debug(debug) { if (debug) { log.enableAll(); } else { log.setLevel(log.levels.ERROR); } } getAudioInputDevices() { return this.device.getAudioInputDevices(); } setAudioInputDevice(deviceId) { this.device.setAudioInputDevice(deviceId); } unsetAudioInputDevice(deviceId) { this.device.unsetAudioInputDevice(deviceId); } getAudioOutputDevices() { return this.device.getAudioOutputDevices(); } getVideoInputDevices() { return this.device.getVideoInputDevices(); } setVideoInputDevice(deviceId) { this.device.setVideoInputDevice(deviceId); } unsetVideoInputDevice(deviceId) { this.device.unsetVideoInputDevice(deviceId); } validateCallsConfigurationId(callsConfigurationId) { if (!callsConfigurationId || typeof (callsConfigurationId) !== 'string' || callsConfigurationId.trim().length === 0) { throw new Error(`Invalid callsConfigurationId '${callsConfigurationId}'`); } } validateStatus(requiredStatus, methodName) { const currentStatus = this.gateway.status; if (requiredStatus !== currentStatus) { throw new Error(`Cannot ${methodName}, required status is ${StatusLabels.get(requiredStatus)}, current status is ${StatusLabels.get(currentStatus)}.`); } } configureEventHandlers() { this.eventEmitter.once('registered', this.handleRegistered.bind(this)); this.eventEmitter.on('registration_failed', this.handleDisconnect.bind(this)); this.eventEmitter.once('disconnected', this.handleDisconnect.bind(this)); this.eventEmitter.on('reconnecting', this.handleReconnecting.bind(this)); this.eventEmitter.on('reconnected', this.handleReconnected.bind(this)); this.eventEmitter.on('application_call', this.handleIncomingApplicationCall.bind(this)); this.eventEmitter.on('call_finished', this.handleHangup.bind(this)); } handleRegistered(event) { var _a; if (event.iceServers) { this.rtcConfig.iceServers = event.iceServers; } let statsUrl = this.rtcOptions.statsUrl || event.apiUrl; this.apiUrl = event.apiUrl; this.logger.setOptions((_a = event.loggerOptions) !== null && _a !== void 0 ? _a : new LoggerOptions()); this.logger.setLogLevel(event.logLevel); this.logger.setApiUrl(statsUrl); this.apiEventEmitter.emit(InfobipRTCEvent.CONNECTED, { identity: event.identity }); } handleIncomingApplicationCall(event) { var _a; if (this.callActive) { return this.apiEventEmitter.emit('call-error', { status: ApplicationErrorCode.BUSY }); } let destination = this.currentUser.identity; this.callActive = true; let callsConfigurationId = event.callsConfigurationId || event.applicationId; if (callsConfigurationId === Properties.WEBRTC_CALLS_CONFIGURATION_ID) { if (((_a = event.internalCustomData) === null || _a === void 0 ? void 0 : _a.type) === FlowType.WEBRTC.toString()) { let incomingCall = new DefaultIncomingWebrtcCall(this.eventEmitter, this.gateway, this.logger, this.rtcConfig, this.device, this.hasRemoteVideo(event.internalCustomData), destination, event.caller.identity, event.description, this.token, this.apiUrl, event.callId); this.apiEventEmitter.emit(InfobipRTCEvent.INCOMING_WEBRTC_CALL, new IncomingWebrtcCallEvent(incomingCall, event.customData)); } else { this.logger.warn(`Received incoming basic call without matching flow type: ${JSON.stringify(event)}`); } } else { let incomingCall = new DefaultIncomingApplicationCall(this.eventEmitter, this.gateway, this.logger, this.rtcConfig, this.device, event.caller, callsConfigurationId, event.description, destination, this.token, this.apiUrl, event.callId); this.apiEventEmitter.emit(InfobipRTCEvent.INCOMING_APPLICATION_CALL, new IncomingApplicationCallEvent(incomingCall, event.customData)); } } hasRemoteVideo(customData) { return "true" === customData.isVideo; } handleHangup(event) { this.callActive = false; } handleReconnecting(event) { this.apiEventEmitter.emit(InfobipRTCEvent.RECONNECTING, {}); } handleReconnected(event) { this.apiEventEmitter.emit(InfobipRTCEvent.RECONNECTED, {}); } handleConnectionClosed(event) { if (this.callActive) { let hangupStatus; if ((event === null || event === void 0 ? void 0 : event.code) === 4000) { hangupStatus = ApplicationErrorCode.NORMAL_HANGUP; } else { hangupStatus = ApplicationErrorCode.NETWORK_ERROR; } this.eventEmitter.emit('hangup', { status: hangupStatus }); } } handleDisconnect(event) { this.handleConnectionClosed(event); this.apiEventEmitter.emit(InfobipRTCEvent.DISCONNECTED, { reason: event.reason }); this.eventEmitter.removeAllListeners('registered'); this.eventEmitter.removeAllListeners('registration_failed'); this.eventEmitter.removeAllListeners('disconnected'); this.eventEmitter.removeAllListeners('reconnecting'); this.eventEmitter.removeAllListeners('reconnected'); this.eventEmitter.removeAllListeners('application_call'); this.eventEmitter.removeAllListeners('hangup'); this.eventEmitter.removeAllListeners('call_finished'); } isWebRTCSupported() { return RTCPeerConnection && (navigator.getUserMedia || (navigator.mediaDevices && navigator.mediaDevices.getUserMedia)); } getUserFromToken(token) { let identity = token.identity; let displayName = token.name; return new User(identity, displayName); } checkIfAnythingIsActive() { if (this.callActive) { throw Error('Call already in progress.'); } } } DefaultInfobipRTC.IDENTITY_PATTERN = /^[\p{L}\p{N}\w.\-_+=/]{3,64}$/u; DefaultInfobipRTC.CONFERENCE_ID_PATTERN = /^[\p{L}\p{N}\w.\-_+=/]{3,250}$/u; DefaultInfobipRTC.PHONE_NUMBER_PATTERN = /^[+]?\p{N}+$/u; //# sourceMappingURL=DefaultInfobipRTC.js.map