Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@signalwire/js

Package Overview
Dependencies
Maintainers
1
Versions
368
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@signalwire/js - npm Package Compare versions

Comparing version 1.3.0-cantina.7 to 1.3.0-cantina.8

dist/esm/common/src/webrtc/ChatChannelHandler.d.ts

5

CHANGELOG.md

@@ -6,2 +6,7 @@ # Changelog

## [Unreleased]
### Removed
- Remove deprecated getters: `devices`, `videoDevices`, `audioInDevices`, `audioOutDevices`.
- Remove deprecated `refreshDevices()` method. Use `getDevices()` instead.
## [1.2.7] - 2020-02-21

@@ -8,0 +13,0 @@ ### Fixed

15

dist/esm/common/src/BaseSession.d.ts
import * as log from 'loglevel';
import Connection from './services/Connection';
import BaseMessage from '../../common/src/messages/BaseMessage';
import { BroadcastParams, ISignalWireOptions, SubscribeParams } from './util/interfaces';
import { BroadcastParams, ISignalWireOptions, SubscribeParams, IBladeAuthorization } from './util/interfaces';
export default abstract class BaseSession {

@@ -9,12 +9,9 @@ options: ISignalWireOptions;

sessionid: string;
subscriptions: {
[channel: string]: any;
};
subscriptions: Map<string, boolean>;
nodeid: string;
master_nodeid: string;
expiresAt: number;
signature: string;
relayProtocol: string;
contexts: string[];
timeoutErrorCode: number;
authorization: IBladeAuthorization;
protected connection: Connection;

@@ -25,2 +22,3 @@ protected _jwtAuth: boolean;

protected _reconnectTimeout: any;
protected _checkTokenExpirationTimeout: any;
protected _autoReconnect: boolean;

@@ -33,2 +31,7 @@ protected _idle: boolean;

get connected(): boolean;
get signature(): string;
get scopeId(): string;
get resource(): string;
get scopes(): string[];
get expiresAt(): number;
get expired(): boolean;

@@ -35,0 +38,0 @@ get reconnectDelay(): number;

59

dist/esm/common/src/BaseSession.js

@@ -17,3 +17,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

import { ADD, REMOVE, SwEvent, BladeMethod } from './util/constants';
import { NOTIFICATION_TYPE } from './webrtc/constants';
import { Notification } from './webrtc/constants';
import { Subscription, Connect, Reauthenticate, Ping } from './messages/Blade';

@@ -28,5 +28,3 @@ import { isFunction, randomInt } from './util/helpers';

this.sessionid = '';
this.subscriptions = {};
this.expiresAt = 0;
this.signature = null;
this.subscriptions = new Map();
this.relayProtocol = null;

@@ -58,2 +56,17 @@ this.contexts = [];

}
get signature() {
return this.authorization ? this.authorization.signature : null;
}
get scopeId() {
return this.authorization ? this.authorization.scope_id : null;
}
get resource() {
return this.authorization ? this.authorization.resource : null;
}
get scopes() {
return this.authorization ? this.authorization.scopes : [];
}
get expiresAt() {
return this.authorization ? +this.authorization.expires_at : 0;
}
get expired() {

@@ -116,3 +129,3 @@ return this.expiresAt && this.expiresAt <= (Date.now() / 1000);

clearTimeout(this._reconnectTimeout);
this.subscriptions = {};
this.subscriptions.clear();
this._autoReconnect = false;

@@ -144,4 +157,3 @@ this.relayProtocol = null;

const response = yield this.execute(br);
const { authorization: { expires_at = null } = {} } = response;
this.expiresAt = +expires_at || 0;
this.authorization = response.authorization || null;
}

@@ -178,5 +190,4 @@ }

this._autoReconnect = true;
const { sessionid, nodeid, master_nodeid, authorization: { expires_at = null, signature = null } = {} } = response;
this.expiresAt = +expires_at || 0;
this.signature = signature;
const { sessionid, nodeid, master_nodeid, authorization } = response;
this.authorization = authorization;
this.relayProtocol = yield Setup(this);

@@ -201,5 +212,6 @@ this._checkTokenExpiration();

for (const sub in this.subscriptions) {
deRegisterAll(sub);
const protocol = sub.split('|')[0];
deRegisterAll(protocol);
}
this.subscriptions = {};
this.subscriptions.clear();
this.contexts = [];

@@ -209,3 +221,3 @@ if (this.expired) {

this._autoReconnect = false;
this.expiresAt = 0;
this.authorization = null;
}

@@ -232,9 +244,8 @@ if (this._autoReconnect) {

if (channel) {
delete this.subscriptions[protocol][channel];
deRegister(protocol, null, channel);
}
else {
delete this.subscriptions[protocol];
deRegisterAll(protocol);
}
this.subscriptions.delete(`${protocol}|${channel}`);
}

@@ -245,17 +256,10 @@ _addSubscription(protocol, handler = null, channel) {

}
if (!this._existsSubscription(protocol)) {
this.subscriptions[protocol] = {};
}
this.subscriptions[protocol][channel] = {};
if (isFunction(handler)) {
register(protocol, handler, channel);
}
this.subscriptions.set(`${protocol}|${channel}`, true);
}
_existsSubscription(protocol, channel) {
if (this.subscriptions.hasOwnProperty(protocol)) {
if (!channel || (channel && this.subscriptions[protocol].hasOwnProperty(channel))) {
return true;
}
}
return false;
const sub = `${protocol}|${channel}`;
return this.subscriptions.has(sub);
}

@@ -299,6 +303,7 @@ _attachListeners() {

logger.warn('Your JWT is going to expire. You should refresh it to keep the session live.');
trigger(SwEvent.Notification, { type: NOTIFICATION_TYPE.refreshToken, session: this }, this.uuid, false);
trigger(SwEvent.Notification, { type: Notification.RefreshToken, session: this }, this.uuid, false);
}
if (!this.expired) {
setTimeout(this._checkTokenExpiration, 30 * 1000);
clearTimeout(this._checkTokenExpirationTimeout);
this._checkTokenExpirationTimeout = setTimeout(this._checkTokenExpiration, 30 * 1000);
}

@@ -305,0 +310,0 @@ }

import BaseSession from './BaseSession';
import { ICacheDevices, IAudioSettings, IVideoSettings, BroadcastParams, SubscribeParams } from './util/interfaces';
import { IWebRTCCall } from './webrtc/interfaces';
import { IAudioSettings, IVideoSettings, BroadcastParams, SubscribeParams } from './util/interfaces';
import BaseMessage from './messages/BaseMessage';
import WebRTCCall from './webrtc/WebRTCCall';
import { IConferenceInfo } from './webrtc/interfaces';
import Conference from './webrtc/Conference';
export default abstract class BrowserSession extends BaseSession {
calls: {
[callId: string]: IWebRTCCall;
[callId: string]: WebRTCCall;
};
conferences: {
[confUuid: string]: Conference;
};
channelToCallIds: Map<string, string[]>;
micId: string;

@@ -13,2 +20,3 @@ micLabel: string;

autoRecoverCalls: boolean;
incognito: boolean;
private _iceServers;

@@ -18,10 +26,12 @@ private _localElement;

protected _jwtAuth: boolean;
protected _devices: ICacheDevices;
protected _audioConstraints: boolean | MediaTrackConstraints;
protected _videoConstraints: boolean | MediaTrackConstraints;
protected _speaker: string;
get callIds(): string[];
addChannelCallIdEntry(channel: string, callId: string): void;
removeChannelCallIdEntry(channel: string, callId: string): void;
get reconnectDelay(): number;
connect(): Promise<void>;
checkPermissions(audio?: boolean, video?: boolean): Promise<boolean>;
logout(): void;
purge(): void;
disconnect(): Promise<void>;

@@ -34,14 +44,6 @@ speedTest(bytes: number): Promise<unknown>;

validateDeviceId(id: string, label: string, kind: MediaDeviceInfo['kind']): Promise<string>;
refreshDevices(): Promise<ICacheDevices>;
get devices(): ICacheDevices;
validateVideoDevice(id: string, label: string): Promise<string>;
validateAudioInDevice(id: string, label: string): Promise<string>;
validateAudioOutDevice(id: string, label: string): Promise<string>;
getDeviceResolutions(deviceId: string): Promise<any[]>;
get videoDevices(): {
[deviceId: string]: MediaDeviceInfo;
};
get audioInDevices(): {
[deviceId: string]: MediaDeviceInfo;
};
get audioOutDevices(): {
[deviceId: string]: MediaDeviceInfo;
};
get mediaConstraints(): {

@@ -65,6 +67,23 @@ audio: boolean | MediaTrackConstraints;

get remoteElement(): HTMLMediaElement | string | Function;
vertoBroadcast({ nodeId, channel: eventChannel, data }: BroadcastParams): void;
vertoSubscribe({ nodeId, channels: eventChannel, handler }: SubscribeParams): Promise<any>;
vertoUnsubscribe({ nodeId, channels: eventChannel }: SubscribeParams): Promise<any>;
vertoBroadcast({ nodeId, channel, data }: BroadcastParams): any;
vertoSubscribe({ nodeId, channels, handler }: SubscribeParams): Promise<any>;
vertoUnsubscribe({ nodeId, channels, handler }: SubscribeParams): Promise<any>;
listConf(): any;
vertoConferenceList(showLayouts?: boolean, showMembers?: boolean): Promise<IConferenceInfo[]>;
vertoLayoutList(options?: {
fullList?: boolean;
}): Promise<{
id: string;
label: string;
type: string;
reservationIds: string[];
belongsToAGroup: boolean;
}[]>;
watchVertoConferences: () => Promise<IConferenceInfo[]>;
unwatchVertoConferences: () => Promise<void>;
dispatchConferenceUpdate(params: any): void;
_jsApi(params?: {}): any;
_wrapInExecute(message: BaseMessage): BaseMessage;
execute(message: BaseMessage): any;
protected _onSocketCloseOrError(event: any): void;
}

@@ -21,12 +21,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

};
import logger from './util/logger';
import BaseSession from './BaseSession';
import { registerOnce, trigger } from './services/Handler';
import { SwEvent, SESSION_ID } from './util/constants';
import { State, DeviceType } from './webrtc/constants';
import { getDevices, scanResolutions, removeUnsupportedConstraints, checkDeviceIdConstraints, destructSubscribeResponse, getUserMedia, assureDeviceId } from './webrtc/helpers';
import { findElementByType } from './util/helpers';
import { State, DeviceType, Notification } from './webrtc/constants';
import { removeUnsupportedConstraints, getUserMedia, destructSubscribeResponse, destructConferenceState, mungeLayoutList } from './webrtc/helpers';
import { getDevices, scanResolutions, checkDeviceIdConstraints, assureDeviceId } from './webrtc/deviceHelpers';
import BaseRequest from './messages/verto/BaseRequest';
import { Execute } from './messages/Blade';
import { Unsubscribe, Subscribe, Broadcast, JSApi } from './messages/Verto';
import { localStorage } from './util/storage/';
import { stopStream } from './util/webrtc';
import laChannelHandler from './webrtc/LaChannelHandler';
import modChannelHandler from './webrtc/ModChannelHandler';
import infoChannelHandler from './webrtc/InfoChannelHandler';
import Conference from './webrtc/Conference';
export default class BrowserSession extends BaseSession {

@@ -36,3 +41,6 @@ constructor() {

this.calls = {};
this.conferences = {};
this.channelToCallIds = new Map();
this.autoRecoverCalls = true;
this.incognito = false;
this._iceServers = [];

@@ -42,7 +50,84 @@ this._localElement = null;

this._jwtAuth = true;
this._devices = {};
this._audioConstraints = true;
this._videoConstraints = false;
this._speaker = null;
this.watchVertoConferences = () => __awaiter(this, void 0, void 0, function* () {
this.conferences = {};
const currentConfList = yield this.vertoConferenceList();
currentConfList.forEach(row => {
this.conferences[row.uuid] = new Conference(this, row);
});
const infoChannel = 'conference-info';
const laChannel = 'conference-liveArray';
const modChannel = 'conference-mod';
const result = yield this.vertoSubscribe({
nodeId: this.nodeid,
channels: [infoChannel, laChannel, modChannel],
});
const { subscribed = [], alreadySubscribed = [] } = destructSubscribeResponse(result);
const all = subscribed.concat(alreadySubscribed);
if (all.includes(laChannel)) {
this._addSubscription(this.relayProtocol, laChannelHandler.bind(this, this), laChannel);
}
if (all.includes(infoChannel)) {
this.on('signalwire.notification', (event) => {
if (event.type !== 'conferenceUpdate') {
return;
}
switch (event.action) {
case 'clear':
Object.keys(this.conferences).forEach(uuid => {
if (this.conferences[uuid].confName === event.confName) {
delete this.conferences[uuid];
}
});
break;
case 'conferenceInfo':
const conferenceState = event.conferenceState;
const { uuid, running } = conferenceState;
if (running) {
this.conferences[uuid] = new Conference(this, conferenceState);
}
else {
delete this.conferences[uuid];
}
break;
}
});
this._addSubscription(this.relayProtocol, infoChannelHandler.bind(this, this), infoChannel);
}
if (all.includes(modChannel)) {
this._addSubscription(this.relayProtocol, modChannelHandler.bind(this, this), modChannel);
}
return currentConfList;
});
this.unwatchVertoConferences = () => __awaiter(this, void 0, void 0, function* () {
this.conferences = {};
const infoChannel = 'conference-info';
const laChannel = 'conference-liveArray';
const modChannel = 'conference-mod';
const channels = [infoChannel, laChannel, modChannel];
channels.forEach(channel => {
this._removeSubscription(this.relayProtocol, channel);
});
yield this.vertoUnsubscribe({
nodeId: this.nodeid,
channels,
});
});
}
get callIds() {
return Object.keys(this.calls);
}
addChannelCallIdEntry(channel, callId) {
const current = this.channelToCallIds.get(channel) || [];
const filtered = current.filter(id => id !== callId);
filtered.push(callId);
this.channelToCallIds.set(channel, filtered);
}
removeChannelCallIdEntry(channel, callId) {
const current = this.channelToCallIds.get(channel) || [];
const filtered = current.filter(id => id !== callId);
this.channelToCallIds.set(channel, filtered);
}
get reconnectDelay() {

@@ -56,3 +141,5 @@ return 1000;

return __awaiter(this, void 0, void 0, function* () {
this.sessionid = yield localStorage.getItem(SESSION_ID);
if (!this.incognito) {
this.sessionid = yield localStorage.getItem(SESSION_ID);
}
_super.connect.call(this);

@@ -73,4 +160,5 @@ });

}
logout() {
this.disconnect();
purge() {
Object.keys(this.calls).forEach(k => this.calls[k].setState(State.Purge));
this.calls = {};
}

@@ -82,4 +170,6 @@ disconnect() {

return __awaiter(this, void 0, void 0, function* () {
Object.keys(this.calls).forEach(k => this.calls[k].setState(State.Purge));
yield _super.disconnect.call(this);
const promises = Object.keys(this.calls).map(k => this.calls[k].hangup());
yield Promise.all(promises);
this.purge();
return _super.disconnect.call(this);
});

@@ -138,49 +228,14 @@ }

}
refreshDevices() {
return __awaiter(this, void 0, void 0, function* () {
logger.warn('This method has been deprecated. Use getDevices() instead.');
const cache = {};
['videoinput', 'audioinput', 'audiooutput'].map((kind) => {
cache[kind] = {};
Object.defineProperty(cache[kind], 'toArray', {
value: function () {
return Object.keys(this).map(k => this[k]);
}
});
});
const devices = yield this.getDevices();
devices.forEach((t) => {
if (cache.hasOwnProperty(t.kind)) {
cache[t.kind][t.deviceId] = t;
}
});
this._devices = cache;
return this.devices;
});
validateVideoDevice(id, label) {
return assureDeviceId(id, label, 'videoinput');
}
get devices() {
return this._devices || {};
validateAudioInDevice(id, label) {
return assureDeviceId(id, label, 'audioinput');
}
validateAudioOutDevice(id, label) {
return assureDeviceId(id, label, 'audiooutput');
}
getDeviceResolutions(deviceId) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield scanResolutions(deviceId);
}
catch (error) {
throw error;
}
});
return scanResolutions(deviceId);
}
get videoDevices() {
logger.warn('This property has been deprecated. Use getVideoDevices() instead.');
return this._devices.videoinput || {};
}
get audioInDevices() {
logger.warn('This property has been deprecated. Use getAudioInDevices() instead.');
return this._devices.audioinput || {};
}
get audioOutDevices() {
logger.warn('This property has been deprecated. Use getAudioOutDevices() instead.');
return this._devices.audiooutput || {};
}
get mediaConstraints() {

@@ -200,2 +255,4 @@ return { audio: this._audioConstraints, video: this._videoConstraints };

disableMicrophone() {
this.micId = null;
this.micLabel = null;
this._audioConstraints = false;

@@ -217,2 +274,4 @@ }

disableWebcam() {
this.camId = null;
this.camLabel = null;
this._videoConstraints = false;

@@ -241,3 +300,3 @@ }

set localElement(tag) {
this._localElement = findElementByType(tag);
this._localElement = tag;
}

@@ -248,3 +307,3 @@ get localElement() {

set remoteElement(tag) {
this._remoteElement = findElementByType(tag);
this._remoteElement = tag;
}

@@ -254,48 +313,129 @@ get remoteElement() {

}
vertoBroadcast({ nodeId, channel: eventChannel = '', data }) {
if (!eventChannel) {
throw new Error('Invalid channel for broadcast: ' + eventChannel);
}
const msg = new Broadcast({ sessid: this.sessionid, eventChannel, data });
vertoBroadcast({ nodeId, channel, data }) {
const msg = new Broadcast({ sessid: this.sessionid, eventChannel: channel, data });
if (nodeId) {
msg.targetNodeId = nodeId;
}
this.execute(msg).catch(error => error);
return this.execute(msg);
}
vertoSubscribe({ nodeId, channels: eventChannel = [], handler }) {
vertoSubscribe({ nodeId, channels, handler = null }) {
return __awaiter(this, void 0, void 0, function* () {
eventChannel = eventChannel.filter(channel => channel && !this._existsSubscription(this.relayProtocol, channel));
if (!eventChannel.length) {
return {};
}
const msg = new Subscribe({ sessid: this.sessionid, eventChannel });
const msg = new Subscribe({ sessid: this.sessionid, eventChannel: channels });
if (nodeId) {
msg.targetNodeId = nodeId;
}
const response = yield this.execute(msg);
const { unauthorized = [], subscribed = [] } = destructSubscribeResponse(response);
if (unauthorized.length) {
unauthorized.forEach(channel => this._removeSubscription(this.relayProtocol, channel));
try {
const response = yield this.execute(msg);
if (handler) {
const { subscribed = [] } = destructSubscribeResponse(response);
subscribed.forEach(channel => this._addSubscription(this.relayProtocol, handler, channel));
}
return response;
}
subscribed.forEach(channel => this._addSubscription(this.relayProtocol, handler, channel));
return response;
catch (error) {
throw error;
}
});
}
vertoUnsubscribe({ nodeId, channels: eventChannel = [] }) {
vertoUnsubscribe({ nodeId, channels, handler = null }) {
return __awaiter(this, void 0, void 0, function* () {
eventChannel = eventChannel.filter(channel => channel && this._existsSubscription(this.relayProtocol, channel));
if (!eventChannel.length) {
return {};
}
const msg = new Unsubscribe({ sessid: this.sessionid, eventChannel });
const msg = new Unsubscribe({ sessid: this.sessionid, eventChannel: channels });
if (nodeId) {
msg.targetNodeId = nodeId;
}
const response = yield this.execute(msg);
const { unsubscribed = [], notSubscribed = [] } = destructSubscribeResponse(response);
unsubscribed.forEach(channel => this._removeSubscription(this.relayProtocol, channel));
notSubscribed.forEach(channel => this._removeSubscription(this.relayProtocol, channel));
return response;
try {
const response = yield this.execute(msg);
if (handler) {
const { unsubscribed = [], notSubscribed = [] } = destructSubscribeResponse(response);
unsubscribed.forEach(channel => this._removeSubscription(this.relayProtocol, channel));
notSubscribed.forEach(channel => this._removeSubscription(this.relayProtocol, channel));
}
return response;
}
catch (error) {
throw error;
}
});
}
listConf() {
const msg = new Execute({
protocol: this.relayProtocol,
method: 'conference.list',
params: {}
});
console.debug('Send confList', msg);
return this.execute(msg);
}
vertoConferenceList(showLayouts = false, showMembers = false) {
return __awaiter(this, void 0, void 0, function* () {
try {
const rooms = [];
const response = yield this._jsApi({
command: 'conference',
data: {
command: 'list',
showLayouts,
showMembers,
},
});
response.conferences.forEach((conf) => {
const { conferenceState, members = [], layouts = [] } = conf;
const room = destructConferenceState(conferenceState);
if (members.length) {
room.members = members.filter(({ type }) => type === 'caller')
.map(({ id, uuid, caller_id_number, caller_id_name }) => {
return {
participantId: Number(id).toString(),
callId: uuid,
participantNumber: caller_id_number,
participantName: caller_id_name,
};
});
}
if (layouts.length) {
const normal = layouts.filter(({ type }) => type === 'layout');
const group = layouts.filter(({ type }) => type === 'layoutGroup');
room.layouts = mungeLayoutList(normal, group);
}
rooms.push(room);
});
return rooms;
}
catch (error) {
console.error('vertoConferenceList error', error);
return [];
}
});
}
vertoLayoutList(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { fullList = false } = options;
try {
const { layouts: { layouts, groups } } = yield this._jsApi({
command: 'conference',
data: {
command: 'listLayouts',
},
});
const final = mungeLayoutList(layouts, groups)
.map((layout) => {
const { id, type } = layout;
const prefix = type === 'group' ? 'group:' : '';
return Object.assign(Object.assign({}, layout), { id: `${prefix}${id}` });
});
if (fullList) {
return final;
}
return final.filter(layout => !layout.belongsToAGroup);
}
catch (error) {
console.error('vertoLayoutList error', error);
return [];
}
});
}
dispatchConferenceUpdate(params) {
const notification = Object.assign({ type: Notification.ConferenceUpdate }, params);
trigger(SwEvent.Notification, notification, this.uuid);
}
_jsApi(params = {}) {

@@ -305,2 +445,19 @@ const msg = new JSApi(Object.assign(Object.assign({}, params), { sessid: this.sessionid }));

}
_wrapInExecute(message) {
const params = {
message: message.request,
node_id: message.targetNodeId || undefined
};
return new Execute({ protocol: this.relayProtocol, method: 'message', params });
}
execute(message) {
if (message instanceof BaseRequest) {
message = this._wrapInExecute(message);
}
return super.execute(message);
}
_onSocketCloseOrError(event) {
this.purge();
super._onSocketCloseOrError(event);
}
}

@@ -33,4 +33,10 @@ import BaseRequest from './verto/BaseRequest';

declare class JSApi extends BaseRequest {
toString(): string;
toString(): VertoMethod;
}
export { Login, Invite, Answer, Attach, Bye, Modify, Info, Broadcast, Subscribe, Unsubscribe, Result, JSApi, };
declare class Stats extends BaseRequest {
toString(): VertoMethod;
}
declare class Ping extends BaseRequest {
toString(): VertoMethod;
}
export { Login, Invite, Answer, Attach, Bye, Modify, Info, Broadcast, Subscribe, Unsubscribe, Result, JSApi, Stats, Ping, };

@@ -52,5 +52,15 @@ import BaseRequest from './verto/BaseRequest';

toString() {
return 'jsapi';
return VertoMethod.JsApi;
}
}
export { Login, Invite, Answer, Attach, Bye, Modify, Info, Broadcast, Subscribe, Unsubscribe, Result, JSApi, };
class Stats extends BaseRequest {
toString() {
return VertoMethod.Stats;
}
}
class Ping extends BaseRequest {
toString() {
return VertoMethod.Ping;
}
}
export { Login, Invite, Answer, Attach, Bye, Modify, Info, Broadcast, Subscribe, Unsubscribe, Result, JSApi, Stats, Ping, };

@@ -12,5 +12,4 @@ import logger from '../util/logger';

if (event_type === 'webrtc.message') {
const handler = new VertoHandler(session);
handler.nodeId = node_id;
handler.handleMessage(params.params);
params.params.nodeId = node_id;
VertoHandler(session, params.params);
}

@@ -17,0 +16,0 @@ else {

@@ -1,8 +0,9 @@

declare const isQueued: (eventName: string, uniqueId?: string) => boolean;
declare const queueLength: (eventName: string, uniqueId?: string) => number;
declare const register: (eventName: string, callback: Function, uniqueId?: string) => void;
declare const registerOnce: (eventName: string, callback: Function, uniqueId?: string) => void;
declare const deRegister: (eventName: string, callback?: Function, uniqueId?: string) => boolean;
declare const trigger: (eventName: string, data: any, uniqueId?: string, globalPropagation?: boolean) => boolean;
declare const deRegisterAll: (eventName: string) => void;
export { trigger, register, registerOnce, deRegister, deRegisterAll, isQueued, queueLength };
declare const isQueued: (event: string, uniqueId?: string) => boolean;
declare const queueLength: (event: string, uniqueId?: string) => number;
declare const register: (event: string, callback: Function, uniqueId?: string) => void;
declare const registerOnce: (event: string, callback: Function, uniqueId?: string) => void;
declare const deRegister: (event: string, callback?: Function, uniqueId?: string) => boolean;
declare const trigger: (event: string, data: any, uniqueId?: string, globalPropagation?: boolean) => boolean;
declare const deRegisterAll: (event: string) => void;
declare const clearQueue: () => void;
export { trigger, register, registerOnce, deRegister, deRegisterAll, isQueued, queueLength, clearQueue };

@@ -1,38 +0,40 @@

import { objEmpty, isFunction } from '../util/helpers';
import { isFunction } from '../util/helpers';
const GLOBAL = 'GLOBAL';
const queue = {};
const isQueued = (eventName, uniqueId = GLOBAL) => queue.hasOwnProperty(eventName) && queue[eventName].hasOwnProperty(uniqueId);
const queueLength = (eventName, uniqueId = GLOBAL) => {
if (!isQueued(eventName, uniqueId)) {
return 0;
}
return queue[eventName][uniqueId].length;
window._queue = queue;
const _buildEventName = (event, uniqueId) => `${event}|${uniqueId}`;
const isQueued = (event, uniqueId = GLOBAL) => {
const eventName = _buildEventName(event, uniqueId);
return eventName in queue;
};
const register = (eventName, callback, uniqueId = GLOBAL) => {
if (!queue.hasOwnProperty(eventName)) {
queue[eventName] = {};
const queueLength = (event, uniqueId = GLOBAL) => {
const eventName = _buildEventName(event, uniqueId);
return eventName in queue ? queue[eventName].length : 0;
};
const register = (event, callback, uniqueId = GLOBAL) => {
const eventName = _buildEventName(event, uniqueId);
if (!(eventName in queue)) {
queue[eventName] = [];
}
if (!queue[eventName].hasOwnProperty(uniqueId)) {
queue[eventName][uniqueId] = [];
}
queue[eventName][uniqueId].push(callback);
queue[eventName].push(callback);
};
const registerOnce = (eventName, callback, uniqueId = GLOBAL) => {
const registerOnce = (event, callback, uniqueId = GLOBAL) => {
const cb = function (data) {
deRegister(eventName, cb, uniqueId);
deRegister(event, cb, uniqueId);
callback(data);
};
cb.prototype.targetRef = callback;
return register(eventName, cb, uniqueId);
return register(event, cb, uniqueId);
};
const deRegister = (eventName, callback, uniqueId = GLOBAL) => {
if (!isQueued(eventName, uniqueId)) {
const deRegister = (event, callback, uniqueId = GLOBAL) => {
if (!isQueued(event, uniqueId)) {
return false;
}
const eventName = _buildEventName(event, uniqueId);
if (isFunction(callback)) {
const len = queue[eventName][uniqueId].length;
const len = queue[eventName].length;
for (let i = len - 1; i >= 0; i--) {
const fn = queue[eventName][uniqueId][i];
const fn = queue[eventName][i];
if (callback === fn || (fn.prototype && callback === fn.prototype.targetRef)) {
queue[eventName][uniqueId].splice(i, 1);
queue[eventName].splice(i, 1);
}

@@ -42,24 +44,22 @@ }

else {
queue[eventName][uniqueId] = [];
queue[eventName] = [];
}
if (queue[eventName][uniqueId].length === 0) {
delete queue[eventName][uniqueId];
if (objEmpty(queue[eventName])) {
delete queue[eventName];
}
if (queue[eventName].length === 0) {
delete queue[eventName];
}
return true;
};
const trigger = (eventName, data, uniqueId = GLOBAL, globalPropagation = true) => {
const trigger = (event, data, uniqueId = GLOBAL, globalPropagation = true) => {
const _propagate = globalPropagation && uniqueId !== GLOBAL;
if (!isQueued(eventName, uniqueId)) {
if (!isQueued(event, uniqueId)) {
if (_propagate) {
trigger(eventName, data);
trigger(event, data);
}
return false;
}
const len = queue[eventName][uniqueId].length;
const eventName = _buildEventName(event, uniqueId);
const len = queue[eventName].length;
if (!len) {
if (_propagate) {
trigger(eventName, data);
trigger(event, data);
}

@@ -69,12 +69,16 @@ return false;

for (let i = len - 1; i >= 0; i--) {
queue[eventName][uniqueId][i](data);
queue[eventName][i](data);
}
if (_propagate) {
trigger(eventName, data);
trigger(event, data);
}
return true;
};
const deRegisterAll = (eventName) => {
delete queue[eventName];
const deRegisterAll = (event) => {
const eventName = _buildEventName(event, '');
Object.keys(queue)
.filter(name => name.indexOf(eventName) === 0)
.forEach(event => delete queue[event]);
};
export { trigger, register, registerOnce, deRegister, deRegisterAll, isQueued, queueLength };
const clearQueue = () => Object.keys(queue).forEach(event => delete queue[event]);
export { trigger, register, registerOnce, deRegister, deRegisterAll, isQueued, queueLength, clearQueue };

@@ -5,2 +5,3 @@ export declare const STORAGE_PREFIX = "@signalwire:";

export declare const SESSION_ID = "sessId";
export declare const VERTO_PROTOCOL = "verto-protocol";
export declare enum SwEvent {

@@ -7,0 +8,0 @@ SocketOpen = "signalwire.socket.open",

@@ -5,2 +5,3 @@ export const STORAGE_PREFIX = '@signalwire:';

export const SESSION_ID = 'sessId';
export const VERTO_PROTOCOL = 'verto-protocol';
export var SwEvent;

@@ -7,0 +8,0 @@ (function (SwEvent) {

export declare const deepCopy: (obj: Object) => any;
export declare const objEmpty: (obj: Object) => boolean;
export declare const mutateStorageKey: (key: string) => string;
export declare const mutateLiveArrayData: (data: any) => any;
export declare const mutateLiveArrayData: (data: any) => {
audio?: any;
video?: any;
connectionState?: any;
variables?: any;
participantId: any;
participantNumber: any;
participantName: any;
codec: any;
participantData: any;
};
export declare const safeParseJson: (value: string) => string | Object;
export declare const isDefined: (variable: any) => boolean;
export declare const isFunction: (variable: any) => boolean;

@@ -14,1 +23,2 @@ export declare const findElementByType: (tag: string | Function | HTMLMediaElement) => HTMLMediaElement;

export declare const randomInt: (min: number, max: number) => number;
export declare const roundToFixed: (value: number, num?: number) => number;

@@ -10,3 +10,3 @@ import logger from './logger';

try {
media = JSON.parse(mediaJson.replace(/ID"/g, 'Id"'));
media = JSON.parse(mediaJson);
}

@@ -16,4 +16,3 @@ catch (error) {

}
const result = { participantId: Number(participantId), participantNumber, participantName, codec, media, participantData };
return result;
return Object.assign({ participantId, participantNumber, participantName, codec, participantData }, media);
};

@@ -31,3 +30,2 @@ export const safeParseJson = (value) => {

};
export const isDefined = (variable) => typeof variable !== 'undefined';
export const isFunction = (variable) => variable instanceof Function || typeof variable === 'function';

@@ -78,1 +76,4 @@ export const findElementByType = (tag) => {

};
export const roundToFixed = (value, num = 2) => {
return Number(value.toFixed(num));
};

@@ -34,2 +34,10 @@ interface IMessageBase {

}
export interface IBladeAuthorization {
expires_at: number;
signature: string;
project: string;
scope_id: string;
scopes: string[];
resource: string;
}
export interface IBladeConnectResult extends IMessageBase {

@@ -40,6 +48,3 @@ sessionid: string;

protocols_uncertified: string[];
authorization: {
expires_at: number;
signature: string;
};
authorization: IBladeAuthorization;
}

@@ -79,3 +84,5 @@ export interface IBladeExecuteRequest extends IMessageBase {

password?: string;
userVariables?: Object;
userVariables?: {
[key: string]: any;
};
}

@@ -82,0 +89,0 @@ export interface SubscribeParams {

@@ -8,3 +8,6 @@ import log from 'loglevel';

return function () {
const messages = [datetime(), '-'];
const messages = [];
if (typeof window === 'undefined') {
messages.push(datetime() + ' -');
}
for (let i = 0; i < arguments.length; i++) {

@@ -11,0 +14,0 @@ messages.push(arguments[i]);

@@ -5,2 +5,3 @@ declare const RTCPeerConnection: (config: RTCConfiguration) => RTCPeerConnection;

declare const enumerateDevices: () => Promise<MediaDeviceInfo[]>;
declare const enumerateDevicesByKind: (filterByKind?: string) => Promise<MediaDeviceInfo[]>;
declare const getSupportedConstraints: () => MediaTrackSupportedConstraints;

@@ -16,2 +17,5 @@ declare const streamIsValid: (stream: MediaStream) => boolean;

declare const stopStream: (stream: MediaStream) => void;
export { RTCPeerConnection, getUserMedia, getDisplayMedia, enumerateDevices, getSupportedConstraints, streamIsValid, attachMediaStream, detachMediaStream, sdpToJsonHack, stopStream, muteMediaElement, unmuteMediaElement, toggleMuteMediaElement, setMediaElementSinkId };
declare const getHostname: () => string;
declare const buildVideoElementByTrack: (videoTrack: MediaStreamTrack, streamIds?: string[]) => HTMLVideoElement;
declare const buildAudioElementByTrack: (audioTrack: MediaStreamTrack, streamIds?: string[]) => HTMLAudioElement;
export { RTCPeerConnection, getUserMedia, getDisplayMedia, enumerateDevices, enumerateDevicesByKind, getSupportedConstraints, streamIsValid, attachMediaStream, detachMediaStream, sdpToJsonHack, stopStream, muteMediaElement, unmuteMediaElement, toggleMuteMediaElement, setMediaElementSinkId, getHostname, buildVideoElementByTrack, buildAudioElementByTrack, };

@@ -11,2 +11,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

import { findElementByType } from '../helpers';
import logger from '../logger';
const RTCPeerConnection = (config) => new window.RTCPeerConnection(config);

@@ -16,2 +17,9 @@ const getUserMedia = (constraints) => navigator.mediaDevices.getUserMedia(constraints);

const enumerateDevices = () => navigator.mediaDevices.enumerateDevices();
const enumerateDevicesByKind = (filterByKind = null) => __awaiter(void 0, void 0, void 0, function* () {
let devices = yield enumerateDevices().catch(error => []);
if (filterByKind) {
devices = devices.filter(({ kind }) => kind === filterByKind);
}
return devices;
});
const getSupportedConstraints = () => navigator.mediaDevices.getSupportedConstraints();

@@ -59,4 +67,9 @@ const streamIsValid = (stream) => stream && stream instanceof MediaStream;

if (element === null) {
logger.info('No HTMLMediaElement to attach the speakerId');
return false;
}
if (typeof deviceId !== 'string') {
logger.info(`Invalid speaker deviceId: '${deviceId}'`);
return false;
}
try {

@@ -82,2 +95,44 @@ yield element.setSinkId(deviceId);

};
export { RTCPeerConnection, getUserMedia, getDisplayMedia, enumerateDevices, getSupportedConstraints, streamIsValid, attachMediaStream, detachMediaStream, sdpToJsonHack, stopStream, muteMediaElement, unmuteMediaElement, toggleMuteMediaElement, setMediaElementSinkId };
const getHostname = () => window.location.hostname;
const buildVideoElementByTrack = (videoTrack, streamIds = []) => {
const video = document.createElement('video');
video.muted = true;
video.autoplay = true;
video.playsinline = true;
video._streamIds = streamIds;
const mediaStream = new MediaStream([videoTrack]);
video.srcObject = mediaStream;
const onCanPlay = () => console.debug('video can play!');
const onPlay = () => console.debug('video is now playing...');
video.addEventListener('play', onPlay);
video.addEventListener('canplay', onCanPlay);
videoTrack.addEventListener('ended', () => {
video.removeEventListener('play', onPlay);
video.removeEventListener('canplay', onCanPlay);
video.srcObject = null;
delete video._streamIds;
video.remove();
});
return video;
};
const buildAudioElementByTrack = (audioTrack, streamIds = []) => {
const audio = new Audio();
audio.autoplay = true;
audio.playsinline = true;
audio._streamIds = streamIds;
const mediaStream = new MediaStream([audioTrack]);
audio.srcObject = mediaStream;
const onCanPlay = () => console.debug('audio can play!');
const onPlay = () => console.debug('audio is now playing...');
audio.addEventListener('play', onPlay);
audio.addEventListener('canplay', onCanPlay);
audioTrack.addEventListener('ended', () => {
audio.removeEventListener('play', onPlay);
audio.removeEventListener('canplay', onCanPlay);
audio.srcObject = null;
delete audio._streamIds;
audio.remove();
});
return audio;
};
export { RTCPeerConnection, getUserMedia, getDisplayMedia, enumerateDevices, enumerateDevicesByKind, getSupportedConstraints, streamIsValid, attachMediaStream, detachMediaStream, sdpToJsonHack, stopStream, muteMediaElement, unmuteMediaElement, toggleMuteMediaElement, setMediaElementSinkId, getHostname, buildVideoElementByTrack, buildAudioElementByTrack, };

@@ -1,11 +0,8 @@

import BaseCall from './BaseCall';
import WebRTCCall from './WebRTCCall';
import { CallOptions } from './interfaces';
export default class Call extends BaseCall {
screenShare: Call;
secondSource: Call;
export default class Call extends WebRTCCall {
private _statsInterval;
hangup(params?: any, execute?: boolean): void;
startScreenShare(opts?: CallOptions): Promise<Call>;
startScreenShare(opts?: CallOptions): Promise<WebRTCCall>;
stopScreenShare(): void;
addSecondSource(opts?: CallOptions): Promise<Call>;
addSecondSource(opts?: CallOptions): Promise<WebRTCCall>;
removeSecondSource(): void;

@@ -12,0 +9,0 @@ setAudioOutDevice(deviceId: string): Promise<boolean>;

@@ -11,5 +11,5 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

import logger from '../util/logger';
import BaseCall from './BaseCall';
import WebRTCCall from './WebRTCCall';
import { getDisplayMedia, setMediaElementSinkId } from '../util/webrtc';
export default class Call extends BaseCall {
export default class Call extends WebRTCCall {
constructor() {

@@ -19,11 +19,2 @@ super(...arguments);

}
hangup(params = {}, execute = true) {
if (this.screenShare instanceof Call) {
this.screenShare.hangup(params, execute);
}
if (this.secondSource instanceof Call) {
this.secondSource.hangup(params, execute);
}
super.hangup(params, execute);
}
startScreenShare(opts) {

@@ -40,4 +31,6 @@ return __awaiter(this, void 0, void 0, function* () {

});
const { remoteCallerName, remoteCallerNumber, callerName, callerNumber } = this.options;
const options = Object.assign({ screenShare: true, recoverCall: false, localStream: displayStream, destinationNumber: `${this.extension};screen`, remoteCallerName, remoteCallerNumber: `${remoteCallerNumber};screen`, callerName: `${callerName} (Screen)`, callerNumber: `${callerNumber} (Screen)` }, opts);
const { destinationNumber, remoteCallerName, remoteCallerNumber, callerName, callerNumber } = this.options;
const options = Object.assign({ screenShare: true, localStream: displayStream, destinationNumber,
remoteCallerName,
remoteCallerNumber, callerName: `${callerName} (Screen)`, callerNumber: `${callerNumber} (Screen)` }, opts);
this.screenShare = new Call(this.session, options);

@@ -55,4 +48,6 @@ this.screenShare.invite();

return __awaiter(this, void 0, void 0, function* () {
const { remoteCallerName, remoteCallerNumber, callerName, callerNumber } = this.options;
const options = Object.assign({ secondSource: true, recoverCall: false, destinationNumber: `${this.extension};second-source`, remoteCallerName, remoteCallerNumber: `${remoteCallerNumber};second-source`, callerName: `${callerName} (Second Source)`, callerNumber: `${callerNumber} (Second Source)`, localStream: null }, opts);
const { destinationNumber, remoteCallerName, remoteCallerNumber, callerName, callerNumber } = this.options;
const options = Object.assign({ secondSource: true, recoverCall: false, destinationNumber,
remoteCallerName,
remoteCallerNumber, callerName: `${callerName} (Second Source)`, callerNumber: `${callerNumber} (Second Source)`, localStream: null }, opts);
this.secondSource = new Call(this.session, options);

@@ -69,10 +64,5 @@ this.secondSource.invite();

setAudioOutDevice(deviceId) {
return __awaiter(this, void 0, void 0, function* () {
this.options.speakerId = deviceId;
const { remoteElement, speakerId } = this.options;
if (remoteElement && speakerId) {
return setMediaElementSinkId(remoteElement, speakerId);
}
return false;
});
this.options.speakerId = deviceId;
const { remoteElement, speakerId } = this.options;
return setMediaElementSinkId(remoteElement, speakerId);
}

@@ -79,0 +69,0 @@ _finalize() {

@@ -1,22 +0,17 @@

import { ICantinaAuthParams, ICantinaUser } from './interfaces';
import { ICantinaUser } from './interfaces';
declare type BootstrapResponse = {
project_id: string;
};
declare type RefreshResponse = {
project: string;
jwt_token: string;
};
declare type CheckInviteTokenResponse = {
valid: boolean;
name: string;
config: object;
};
declare class CantinaAuth {
private params;
baseUrl: string;
hostname: string;
constructor(params?: ICantinaAuthParams);
private _fetch;
userLogin(username: string, password: string): Promise<ICantinaUser>;
guestLogin(name: string, email: string, token: string): Promise<ICantinaUser>;
refresh(): Promise<RefreshResponse>;
checkInviteToken(token: string): Promise<CheckInviteTokenResponse>;
bootstrap(hostname: string): Promise<BootstrapResponse>;
login(username: string, project_id: string): Promise<ICantinaUser>;
refresh(refreshToken?: any): Promise<RefreshResponse>;
logout(): Promise<void>;
}
export default CantinaAuth;

@@ -19,9 +19,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

class CantinaAuth {
constructor(params = {}) {
this.params = params;
this.baseUrl = 'https://cantina-backend.signalwire.com';
constructor() {
this.baseUrl = '';
this._fetch = (url, options) => {
return fetch(url, options).then((response) => __awaiter(this, void 0, void 0, function* () {
const payload = yield response.json();
if (response.status >= 200 && response.status < 300) {
if (response.status === 204) {
return response;
}
const payload = yield response.json();
return payload;

@@ -32,3 +34,3 @@ }

const error = new Error(errorMessage);
error.payload = payload;
error.response = response;
return Promise.reject(error);

@@ -38,22 +40,26 @@ }

};
const { hostname = location.hostname } = params;
this.hostname = hostname;
}
userLogin(username, password) {
bootstrap(hostname) {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this._fetch(`${this.baseUrl}/login/user`, Object.assign(Object.assign({}, FETCH_OPTIONS), { body: JSON.stringify({ username, password, hostname: this.hostname }) }));
logger.info('userLogin response', response);
const clear = encodeURIComponent(hostname);
const url = `${this.baseUrl}/api/configuration?hostname=${clear}`;
const response = yield this._fetch(url, Object.assign(Object.assign({}, FETCH_OPTIONS), { method: 'GET' }));
logger.info('bootstrap response', response);
return response;
});
}
guestLogin(name, email, token) {
login(username, project_id) {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this._fetch(`${this.baseUrl}/login/guest`, Object.assign(Object.assign({}, FETCH_OPTIONS), { body: JSON.stringify({ name, email, token, hostname: this.hostname }) }));
logger.info('guestLogin response', response);
const response = yield this._fetch(`${this.baseUrl}/api/login`, Object.assign(Object.assign({}, FETCH_OPTIONS), { body: JSON.stringify({ username, project_id }) }));
logger.info('userLogin response', response);
return response;
});
}
refresh() {
refresh(refreshToken = null) {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this._fetch(`${this.baseUrl}/refresh`, Object.assign(Object.assign({}, FETCH_OPTIONS), { method: 'PUT', body: JSON.stringify({ hostname: this.hostname }) }));
const options = Object.assign(Object.assign({}, FETCH_OPTIONS), { method: 'PUT' });
if (refreshToken) {
options.body = JSON.stringify({ refresh_token: refreshToken });
}
const response = yield this._fetch(`${this.baseUrl}/api/refresh`, options);
logger.info('refresh response', response);

@@ -63,6 +69,6 @@ return response;

}
checkInviteToken(token) {
logout() {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this._fetch(`${this.baseUrl}/check-token`, Object.assign(Object.assign({}, FETCH_OPTIONS), { body: JSON.stringify({ token, hostname: this.hostname }) }));
logger.info('checkInviteToken response', response);
const response = yield this._fetch(`${this.baseUrl}/api/logout`, Object.assign(Object.assign({}, FETCH_OPTIONS), { method: 'PUT' }));
logger.info('logout response', response);
return response;

@@ -69,0 +75,0 @@ });

@@ -26,15 +26,20 @@ import { CallOptions } from './interfaces';

MediaParams = "verto.mediaParams",
Prompt = "verto.prompt"
Prompt = "verto.prompt",
JsApi = "jsapi",
Stats = "verto.stats",
Ping = "verto.ping",
Announce = "verto.announce"
}
export declare const NOTIFICATION_TYPE: {
generic: string;
prompt: string;
"verto.display": string;
"verto.attach": string;
conferenceUpdate: string;
callUpdate: string;
vertoClientReady: string;
userMediaError: string;
refreshToken: string;
};
export declare enum Notification {
Generic = "event",
ParticipantData = "participantData",
ConferenceUpdate = "conferenceUpdate",
CallUpdate = "callUpdate",
VertoClientReady = "vertoClientReady",
UserMediaError = "userMediaError",
RefreshToken = "refreshToken",
Prompt = "prompt",
Announce = "announce",
DeviceUpdated = "deviceUpdated"
}
export declare const DEFAULT_CALL_OPTIONS: CallOptions;

@@ -51,5 +56,5 @@ export declare enum State {

Held = 8,
Purge = 9,
Hangup = 10,
Destroy = 11
Hangup = 9,
Destroy = 10,
Purge = 11
}

@@ -73,4 +78,5 @@ export declare enum Role {

LayoutList = "layoutList",
ModCmdResponse = "modCommandResponse",
ConferenceInfo = "conferenceInfo",
ModCmdResponse = "modCommandResponse"
CaptionInfo = "captionInfo"
}

@@ -77,0 +83,0 @@ export declare enum DeviceType {

@@ -29,14 +29,20 @@ export var PeerType;

VertoMethod["Prompt"] = "verto.prompt";
VertoMethod["JsApi"] = "jsapi";
VertoMethod["Stats"] = "verto.stats";
VertoMethod["Ping"] = "verto.ping";
VertoMethod["Announce"] = "verto.announce";
})(VertoMethod || (VertoMethod = {}));
export const NOTIFICATION_TYPE = {
generic: 'event',
prompt: 'prompt',
[VertoMethod.Display]: 'participantData',
[VertoMethod.Attach]: 'participantData',
conferenceUpdate: 'conferenceUpdate',
callUpdate: 'callUpdate',
vertoClientReady: 'vertoClientReady',
userMediaError: 'userMediaError',
refreshToken: 'refreshToken',
};
export var Notification;
(function (Notification) {
Notification["Generic"] = "event";
Notification["ParticipantData"] = "participantData";
Notification["ConferenceUpdate"] = "conferenceUpdate";
Notification["CallUpdate"] = "callUpdate";
Notification["VertoClientReady"] = "vertoClientReady";
Notification["UserMediaError"] = "userMediaError";
Notification["RefreshToken"] = "refreshToken";
Notification["Prompt"] = "prompt";
Notification["Announce"] = "announce";
Notification["DeviceUpdated"] = "deviceUpdated";
})(Notification || (Notification = {}));
export const DEFAULT_CALL_OPTIONS = {

@@ -55,2 +61,4 @@ destinationNumber: '',

userVariables: {},
requestTimeout: 10 * 1000,
experimental: false,
};

@@ -68,5 +76,5 @@ export var State;

State[State["Held"] = 8] = "Held";
State[State["Purge"] = 9] = "Purge";
State[State["Hangup"] = 10] = "Hangup";
State[State["Destroy"] = 11] = "Destroy";
State[State["Hangup"] = 9] = "Hangup";
State[State["Destroy"] = 10] = "Destroy";
State[State["Purge"] = 11] = "Purge";
})(State || (State = {}));

@@ -92,4 +100,5 @@ export var Role;

ConferenceAction["LayoutList"] = "layoutList";
ConferenceAction["ModCmdResponse"] = "modCommandResponse";
ConferenceAction["ConferenceInfo"] = "conferenceInfo";
ConferenceAction["ModCmdResponse"] = "modCommandResponse";
ConferenceAction["CaptionInfo"] = "captionInfo";
})(ConferenceAction || (ConferenceAction = {}));

@@ -96,0 +105,0 @@ export var DeviceType;

@@ -1,12 +0,5 @@

import { CallOptions } from './interfaces';
declare const getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;
declare const getDevices: (kind?: string, fullList?: boolean) => Promise<MediaDeviceInfo[]>;
declare const scanResolutions: (deviceId: string) => Promise<any[]>;
declare const getMediaConstraints: (options: CallOptions) => Promise<MediaStreamConstraints>;
declare const assureDeviceId: (id: string, label: string, kind: MediaDeviceKind) => Promise<string>;
declare const removeUnsupportedConstraints: (constraints: MediaTrackConstraints) => void;
declare const checkDeviceIdConstraints: (id: string, label: string, kind: MediaDeviceKind, constraints: MediaTrackConstraints) => Promise<MediaTrackConstraints>;
declare const sdpStereoHack: (sdp: string) => string;
declare const sdpMediaOrderHack: (answer: string, localOffer: string) => string;
declare const checkSubscribeResponse: (response: any, channel: string) => boolean;
import { CallOptions, IVertoCanvasInfo, ICanvasInfo, IConferenceInfo, ILayout, IVertoLayout } from './interfaces';
export declare const getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;
export declare const removeUnsupportedConstraints: (constraints: MediaTrackConstraints) => void;
export declare const getMediaConstraints: (options: CallOptions) => Promise<MediaStreamConstraints>;
declare type DestructuredResult = {

@@ -19,10 +12,15 @@ subscribed: string[];

};
declare const destructSubscribeResponse: (response: any) => DestructuredResult;
declare const enableAudioTracks: (stream: MediaStream) => void;
declare const disableAudioTracks: (stream: MediaStream) => void;
declare const toggleAudioTracks: (stream: MediaStream) => void;
declare const enableVideoTracks: (stream: MediaStream) => void;
declare const disableVideoTracks: (stream: MediaStream) => void;
declare const toggleVideoTracks: (stream: MediaStream) => void;
declare const sdpBitrateHack: (sdp: string, max: number, min: number, start: number) => string;
export { getUserMedia, getDevices, scanResolutions, getMediaConstraints, assureDeviceId, removeUnsupportedConstraints, checkDeviceIdConstraints, sdpStereoHack, sdpMediaOrderHack, sdpBitrateHack, checkSubscribeResponse, destructSubscribeResponse, enableAudioTracks, disableAudioTracks, toggleAudioTracks, enableVideoTracks, disableVideoTracks, toggleVideoTracks, };
export declare const destructSubscribeResponse: (response: any) => DestructuredResult;
export declare const enableAudioTracks: (stream: MediaStream) => void;
export declare const disableAudioTracks: (stream: MediaStream) => void;
export declare const toggleAudioTracks: (stream: MediaStream) => void;
export declare const enableVideoTracks: (stream: MediaStream) => void;
export declare const disableVideoTracks: (stream: MediaStream) => void;
export declare const toggleVideoTracks: (stream: MediaStream) => void;
export declare const mutateCanvasInfoData: (canvasInfo: IVertoCanvasInfo) => ICanvasInfo;
export declare const checkIsDirectCall: ({ variables }: {
variables: any;
}) => boolean;
export declare const destructConferenceState: (confState: any) => IConferenceInfo;
export declare const mungeLayoutList: (layouts: IVertoLayout[], layoutGroups: IVertoLayout[]) => ILayout[];
export {};

@@ -10,7 +10,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import logger from '../util/logger';
import * as WebRTC from '../util/webrtc';
import { isDefined } from '../util/helpers';
import { roundToFixed } from '../util/helpers';
import { assureDeviceId } from './deviceHelpers';
import { DeviceType } from './constants';
const getUserMedia = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
export const getUserMedia = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
logger.info('RTCService.getUserMedia', constraints);

@@ -29,54 +41,11 @@ const { audio, video } = constraints;

});
const _constraintsByKind = (kind = null) => {
return {
audio: !kind || kind === DeviceType.AudioIn,
video: !kind || kind === DeviceType.Video
};
};
const getDevices = (kind = null, fullList = false) => __awaiter(void 0, void 0, void 0, function* () {
let devices = yield WebRTC.enumerateDevices().catch(error => []);
if (kind) {
devices = devices.filter((d) => d.kind === kind);
}
const valid = devices.length && devices.every((d) => (d.deviceId && d.label));
if (!valid) {
const stream = yield WebRTC.getUserMedia(_constraintsByKind(kind));
WebRTC.stopStream(stream);
return getDevices(kind);
}
if (fullList === true) {
return devices;
}
const found = [];
devices = devices.filter(({ kind, groupId }) => {
if (!groupId) {
return true;
export const removeUnsupportedConstraints = (constraints) => {
const supported = WebRTC.getSupportedConstraints();
Object.keys(constraints).map(key => {
if (!supported.hasOwnProperty(key) || constraints[key] === null || constraints[key] === undefined) {
delete constraints[key];
}
const key = `${kind}-${groupId}`;
if (!found.includes(key)) {
found.push(key);
return true;
}
return false;
});
return devices;
});
const resolutionList = [[320, 240], [640, 360], [640, 480], [1280, 720], [1920, 1080]];
const scanResolutions = (deviceId) => __awaiter(void 0, void 0, void 0, function* () {
const supported = [];
const stream = yield getUserMedia({ video: { deviceId: { exact: deviceId } } });
const videoTrack = stream.getVideoTracks()[0];
for (let i = 0; i < resolutionList.length; i++) {
const [width, height] = resolutionList[i];
const success = yield videoTrack.applyConstraints({ width: { exact: width }, height: { exact: height } })
.then(() => true)
.catch(() => false);
if (success) {
supported.push({ resolution: `${width}x${height}`, width, height });
}
}
WebRTC.stopStream(stream);
return supported;
});
const getMediaConstraints = (options) => __awaiter(void 0, void 0, void 0, function* () {
};
export const getMediaConstraints = (options) => __awaiter(void 0, void 0, void 0, function* () {
let { audio = true, micId } = options;

@@ -106,81 +75,3 @@ const { micLabel = '' } = options;

});
const assureDeviceId = (id, label, kind) => __awaiter(void 0, void 0, void 0, function* () {
const devices = yield getDevices(kind, true);
for (let i = 0; i < devices.length; i++) {
const { deviceId, label: deviceLabel } = devices[i];
if (id === deviceId || label === deviceLabel) {
return deviceId;
}
}
return null;
});
const removeUnsupportedConstraints = (constraints) => {
const supported = WebRTC.getSupportedConstraints();
Object.keys(constraints).map(key => {
if (!supported.hasOwnProperty(key) || constraints[key] === null || constraints[key] === undefined) {
delete constraints[key];
}
});
};
const checkDeviceIdConstraints = (id, label, kind, constraints) => __awaiter(void 0, void 0, void 0, function* () {
const { deviceId } = constraints;
if (!isDefined(deviceId) && (id || label)) {
const deviceId = yield assureDeviceId(id, label, kind).catch(error => null);
if (deviceId) {
constraints.deviceId = { exact: deviceId };
}
}
return constraints;
});
const sdpStereoHack = (sdp) => {
const endOfLine = '\r\n';
const sdpLines = sdp.split(endOfLine);
const opusIndex = sdpLines.findIndex(s => /^a=rtpmap/.test(s) && /opus\/48000/.test(s));
if (opusIndex < 0) {
return sdp;
}
const getCodecPayloadType = (line) => {
const pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');
const result = line.match(pattern);
return result && result.length == 2 ? result[1] : null;
};
const opusPayload = getCodecPayloadType(sdpLines[opusIndex]);
const pattern = new RegExp(`a=fmtp:${opusPayload}`);
const fmtpLineIndex = sdpLines.findIndex(s => pattern.test(s));
if (fmtpLineIndex >= 0) {
if (!/stereo=1;/.test(sdpLines[fmtpLineIndex])) {
sdpLines[fmtpLineIndex] += '; stereo=1; sprop-stereo=1';
}
}
else {
sdpLines[opusIndex] += `${endOfLine}a=fmtp:${opusPayload} stereo=1; sprop-stereo=1`;
}
return sdpLines.join(endOfLine);
};
const _isAudioLine = (line) => /^m=audio/.test(line);
const _isVideoLine = (line) => /^m=video/.test(line);
const sdpMediaOrderHack = (answer, localOffer) => {
const endOfLine = '\r\n';
const offerLines = localOffer.split(endOfLine);
const offerAudioIndex = offerLines.findIndex(_isAudioLine);
const offerVideoIndex = offerLines.findIndex(_isVideoLine);
if (offerAudioIndex < offerVideoIndex) {
return answer;
}
const answerLines = answer.split(endOfLine);
const answerAudioIndex = answerLines.findIndex(_isAudioLine);
const answerVideoIndex = answerLines.findIndex(_isVideoLine);
const audioLines = answerLines.slice(answerAudioIndex, answerVideoIndex);
const videoLines = answerLines.slice(answerVideoIndex, (answerLines.length - 1));
const beginLines = answerLines.slice(0, answerAudioIndex);
return [...beginLines, ...videoLines, ...audioLines, ''].join(endOfLine);
};
const checkSubscribeResponse = (response, channel) => {
if (!response) {
return false;
}
const { subscribed, alreadySubscribed } = destructSubscribeResponse(response);
return subscribed.includes(channel) || alreadySubscribed.includes(channel);
};
const destructSubscribeResponse = (response) => {
export const destructSubscribeResponse = (response) => {
const tmp = {

@@ -196,20 +87,2 @@ subscribed: [],

};
const enableAudioTracks = (stream) => {
_updateMediaStreamTracks(stream, 'audio', true);
};
const disableAudioTracks = (stream) => {
_updateMediaStreamTracks(stream, 'audio', false);
};
const toggleAudioTracks = (stream) => {
_updateMediaStreamTracks(stream, 'audio', null);
};
const enableVideoTracks = (stream) => {
_updateMediaStreamTracks(stream, 'video', true);
};
const disableVideoTracks = (stream) => {
_updateMediaStreamTracks(stream, 'video', false);
};
const toggleVideoTracks = (stream) => {
_updateMediaStreamTracks(stream, 'video', null);
};
const _updateMediaStreamTracks = (stream, kind = null, enabled = null) => {

@@ -219,21 +92,7 @@ if (!WebRTC.streamIsValid(stream)) {

}
let tracks = [];
switch (kind) {
case 'audio':
tracks = stream.getAudioTracks();
break;
case 'video':
tracks = stream.getVideoTracks();
break;
default:
tracks = stream.getTracks();
break;
}
tracks.forEach((track) => {
const _updateTrack = (track) => {
switch (enabled) {
case 'on':
case true:
track.enabled = true;
break;
case 'off':
case false:

@@ -246,17 +105,104 @@ track.enabled = false;

}
});
};
switch (kind) {
case 'audio':
return stream.getAudioTracks().forEach(_updateTrack);
case 'video':
return stream.getVideoTracks().forEach(_updateTrack);
default:
return stream.getTracks().forEach(_updateTrack);
}
};
const sdpBitrateHack = (sdp, max, min, start) => {
const endOfLine = '\r\n';
const lines = sdp.split(endOfLine);
lines.forEach((line, i) => {
if (/^a=fmtp:\d*/.test(line)) {
lines[i] += `;x-google-max-bitrate=${max};x-google-min-bitrate=${min};x-google-start-bitrate=${start}`;
}
else if (/^a=mid:(1|video)/.test(line)) {
lines[i] += `\r\nb=AS:${max}`;
}
export const enableAudioTracks = (stream) => _updateMediaStreamTracks(stream, 'audio', true);
export const disableAudioTracks = (stream) => _updateMediaStreamTracks(stream, 'audio', false);
export const toggleAudioTracks = (stream) => _updateMediaStreamTracks(stream, 'audio', null);
export const enableVideoTracks = (stream) => _updateMediaStreamTracks(stream, 'video', true);
export const disableVideoTracks = (stream) => _updateMediaStreamTracks(stream, 'video', false);
export const toggleVideoTracks = (stream) => _updateMediaStreamTracks(stream, 'video', null);
export const mutateCanvasInfoData = (canvasInfo) => {
const { canvasID, layoutFloorID, scale, canvasLayouts } = canvasInfo, rest = __rest(canvasInfo, ["canvasID", "layoutFloorID", "scale", "canvasLayouts"]);
const layouts = [];
let layoutOverlap = false;
for (let i = 0; i < canvasLayouts.length; i++) {
const layout = canvasLayouts[i];
const { memberID, audioPOS, xPOS, yPOS } = layout, rest = __rest(layout, ["memberID", "audioPOS", "xPOS", "yPOS"]);
layoutOverlap = layoutOverlap || layout.overlap === 1;
layouts.push(Object.assign({ startX: `${roundToFixed((layout.x / scale) * 100)}%`, startY: `${roundToFixed((layout.y / scale) * 100)}%`, percentageWidth: `${roundToFixed((layout.scale / scale) * 100)}%`, percentageHeight: `${roundToFixed((layout.hscale / scale) * 100)}%`, participantId: String(memberID), audioPos: audioPOS, xPos: xPOS, yPos: yPOS }, rest));
}
return Object.assign(Object.assign({}, rest), { canvasId: canvasID, layoutFloorId: layoutFloorID, scale, canvasLayouts: layouts, layoutOverlap });
};
export const checkIsDirectCall = ({ variables }) => {
return typeof variables === 'object' && 'verto_svar_direct_call' in variables;
};
export const destructConferenceState = (confState) => {
const { variables = {}, flags = {} } = confState;
const suffix = `${confState.md5}@${confState.domain}`;
return {
uuid: confState.uuid,
md5: confState.md5,
domain: confState.domain,
running: Boolean(confState.running),
laChannel: `conference-liveArray.${suffix}`,
infoChannel: `conference-info.${suffix}`,
modChannel: `conference-mod.${suffix}`,
confName: confState.name,
numMembers: Number(confState.members) || 0,
isPrivate: variables.is_private === 'true',
mohPlaying: Boolean(confState.mohPlaying),
filesPlaying: Boolean(confState.filesPlaying),
filesPlayingName: confState.filesPlayingName || null,
asyncFilesPlaying: Boolean(confState.asyncFilesPlaying),
asyncFilesPlayingName: confState.asyncFilesPlayingName || null,
asyncFilesPlayingPaused: Boolean(confState.asyncFilesPlayingPaused),
asyncFilesPlayingVolume: Number(confState.asyncFilesPlayingVolume) || null,
filesSeekable: Boolean(confState.filesSeekable),
asyncFilesSeekable: Boolean(confState.asyncFilesSeekable),
performerDelay: confState.performerDelay,
volAudience: confState['vol-audience'],
filesFullScreen: Boolean(confState.filesFullScreen),
silentMode: flags['silent-mode'] || false,
meetingMode: flags['meeting-mode'] || false,
vidMuteHide: flags['vid-mute-hide'] || false,
personalCanvas: Boolean(flags.personalCanvas),
personalCanvasTP: flags.personalCanvasTP || null,
locked: Boolean(flags.locked),
recording: Boolean(flags.recording),
liveMusic: Boolean(flags.liveMusic),
publicClipeeze: variables.public_clipeeze === 'true',
confQuality: variables.conf_quality,
accessPin: variables.access_pin || null,
moderatorPin: variables.moderator_pin || null,
speakerHighlight: variables.speaker_highlight === 'true',
disableIntercom: variables.disable_intercom === true,
lastSnapshot: variables.lastSnapshot,
lastLayoutGroup: variables.lastLayoutGroup,
lastLayout: variables.lastLayout,
};
};
const _layoutReducer = (result, layout) => {
const { type, name, displayName, resIDS = [] } = layout;
const label = displayName || name.replace(/[-_]/g, ' ');
return result.concat({ id: name, label, type, reservationIds: resIDS, belongsToAGroup: false });
};
function _layoutCompare(prev, next) {
const prevLabel = prev.label.toLowerCase();
const nextLabel = next.label.toLowerCase();
if (prevLabel > nextLabel) {
return 1;
}
else if (prevLabel < nextLabel) {
return -1;
}
return 0;
}
export const mungeLayoutList = (layouts, layoutGroups) => {
const layoutsPartOfGroup = layoutGroups.reduce((cumulative, layout) => {
return cumulative.concat(layout.groupLayouts || []);
}, []);
const normalList = layouts.reduce(_layoutReducer, []);
normalList.forEach((layout) => {
layout.belongsToAGroup = layoutsPartOfGroup.includes(layout.id);
});
return lines.join(endOfLine);
const groupList = layoutGroups.reduce(_layoutReducer, []);
return groupList.concat(normalList).sort(_layoutCompare);
};
export { getUserMedia, getDevices, scanResolutions, getMediaConstraints, assureDeviceId, removeUnsupportedConstraints, checkDeviceIdConstraints, sdpStereoHack, sdpMediaOrderHack, sdpBitrateHack, checkSubscribeResponse, destructSubscribeResponse, enableAudioTracks, disableAudioTracks, toggleAudioTracks, enableVideoTracks, disableVideoTracks, toggleVideoTracks, };

@@ -23,3 +23,5 @@ export interface CallOptions {

speakerId?: string;
userVariables?: Object;
userVariables?: {
[key: string]: any;
};
screenShare?: boolean;

@@ -32,52 +34,12 @@ secondSource?: boolean;

googleStartBitrate?: number;
negotiateAudio?: boolean;
negotiateVideo?: boolean;
sfu?: boolean;
simulcast?: boolean;
msStreamsNumber?: number;
requestTimeout?: number;
shakenCheck?: string;
shakenResult?: string;
experimental?: boolean;
}
export interface IWebRTCCall {
id: string;
state: string;
prevState: string;
direction: string;
options: CallOptions;
cause: string;
causeCode: number;
channels: string[];
role: string;
extension: string;
localStream: MediaStream;
remoteStream: MediaStream;
isMainCall: boolean;
invite: () => void;
answer: () => void;
hangup: (params: any, execute: boolean) => void;
transfer: (destination: string) => void;
replace: (replaceCallID: string) => void;
hold: () => void;
unhold: () => void;
toggleHold: () => void;
dtmf: (dtmf: string) => void;
message: (to: string, body: string) => void;
muteAudio: () => void;
unmuteAudio: () => void;
toggleAudioMute: () => void;
setAudioInDevice: (deviceId: string) => Promise<void>;
muteVideo: () => void;
unmuteVideo: () => void;
toggleVideoMute: () => void;
setVideoDevice: (deviceId: string) => Promise<void>;
deaf: () => void;
undeaf: () => void;
toggleDeaf: () => void;
setState: (state: any) => void;
destroy: () => void;
handleMessage: (msg: any) => void;
_addChannel: (laChannel: any) => void;
handleConferenceUpdate: (packet: any, pvtData: any) => Promise<string>;
startScreenShare?: (opts?: object) => Promise<IWebRTCCall>;
stopScreenShare?: () => void;
setAudioOutDevice?: (deviceId: string) => Promise<boolean>;
switchCamera?: () => void;
setSpeakerPhone?: (flag: boolean) => void;
}
export interface ICantinaAuthParams {
hostname?: string;
}
export interface ICantinaUser {

@@ -94,1 +56,145 @@ first_name: string;

}
export interface VertoPvtData {
callID: string;
nodeId?: string;
action: string;
laChannel: string;
laName: string;
role: string;
chatID: string;
conferenceMemberID: number;
canvasCount: string;
modChannel: string;
chatChannel: string;
infoChannel: string;
}
export interface IVertoCanvasInfo {
canvasID: number;
totalLayers: number;
layersUsed: number;
layoutFloorID: number;
layoutName: string;
canvasLayouts: IVertoCanvasLayout[];
scale: number;
}
export interface IVertoCanvasLayout {
x: number;
y: number;
scale: number;
hscale: number;
zoom: number;
border: number;
floor: number;
overlap: number;
screenWidth: number;
screenHeight: number;
xPOS: number;
yPOS: number;
audioPOS: string;
memberID: number;
}
export interface ICanvasInfo {
canvasId: number;
totalLayers: number;
layersUsed: number;
layoutFloorId: number;
layoutName: string;
canvasLayouts: ICanvasLayout[];
scale: number;
layoutOverlap: boolean;
}
export interface ICanvasLayout {
x: number;
y: number;
startX: string;
startY: string;
percentageWidth: string;
percentageHeight: string;
scale: number;
hscale: number;
zoom: number;
border: number;
floor: number;
overlap: number;
screenWidth: number;
screenHeight: number;
xPos: number;
yPos: number;
audioPos: string;
participantId: string;
}
export interface IHangupParams {
code?: string;
cause?: string;
redirectDestination?: any;
}
export interface ICallParticipant {
id: string;
role: string;
layer: ICanvasLayout;
layerIndex: number;
isLayerBehind: boolean;
}
export interface IConferenceInfoMember {
participantId: string;
callId: string;
participantNumber: string;
participantName: string;
}
export interface IConferenceInfo {
uuid: string;
md5: string;
domain: string;
running: boolean;
laChannel: string;
infoChannel: string;
modChannel: string;
confName: string;
numMembers: number;
isPrivate: boolean;
mohPlaying: boolean;
filesPlaying: boolean;
filesPlayingName: string;
asyncFilesPlaying: boolean;
asyncFilesPlayingName: string;
asyncFilesPlayingPaused: boolean;
asyncFilesPlayingVolume: number;
filesSeekable: boolean;
asyncFilesSeekable: boolean;
performerDelay: number;
volAudience: number;
filesFullScreen: boolean;
silentMode: boolean;
meetingMode: boolean;
locked: boolean;
recording: boolean;
personalCanvas: boolean;
personalCanvasTP: number;
liveMusic: boolean;
vidMuteHide: boolean;
publicClipeeze: boolean;
confQuality: string;
accessPin: string;
moderatorPin: string;
speakerHighlight: boolean;
disableIntercom: boolean;
lastSnapshot: string;
lastLayoutGroup: string;
lastLayout: string;
members?: IConferenceInfoMember[];
layouts?: any;
}
export interface ILayout {
id: string;
label: string;
type: string;
reservationIds: string[];
belongsToAGroup: boolean;
}
export interface IVertoLayout {
name: string;
displayName?: string;
type: string;
resIDS: string[];
groupLayouts?: string[];
}
import BrowserSession from '../BrowserSession';
declare class VertoHandler {
session: BrowserSession;
nodeId: string;
constructor(session: BrowserSession);
private _ack;
handleMessage(msg: any): Promise<void>;
private _retrieveCallId;
private _handlePvtEvent;
private _handleSessionEvent;
}
export default VertoHandler;
declare const _default: (session: BrowserSession, msg: any) => any;
export default _default;

@@ -12,200 +12,146 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

import Call from './Call';
import { checkSubscribeResponse } from './helpers';
import { Result } from '../messages/Verto';
import { SwEvent } from '../util/constants';
import { VertoMethod, NOTIFICATION_TYPE } from './constants';
import { trigger, deRegister } from '../services/Handler';
import { State, ConferenceAction } from './constants';
import { MCULayoutEventHandler } from './LayoutHandler';
class VertoHandler {
constructor(session) {
this.session = session;
import { VertoMethod, Notification } from './constants';
import { trigger } from '../services/Handler';
import { State } from './constants';
import { checkIsDirectCall } from './helpers';
const _handlePvtEvent = (session, pvtData) => __awaiter(void 0, void 0, void 0, function* () {
const { action, callID } = pvtData;
if (!callID || !session.calls[callID]) {
return logger.debug('Verto pvtData with invalid or unknown callID.', pvtData);
}
_ack(id, method) {
const msg = new Result(id, method);
if (this.nodeId) {
msg.targetNodeId = this.nodeId;
const call = session.calls[callID];
if (!call.isMainCall) {
return logger.debug('Verto pvtData on screenShare or secondSource legs.', pvtData);
}
switch (action) {
case 'conference-liveArray-join':
yield call.conferenceJoinHandler(pvtData);
break;
case 'conference-liveArray-part':
yield call.conferencePartHandler(pvtData);
break;
}
});
const _handleSessionEvent = (session, eventData) => {
const { contentType, callID } = eventData;
if (!callID || !session.calls.hasOwnProperty(callID)) {
return logger.debug('Unhandled session event:', eventData);
}
const call = session.calls[callID];
switch (contentType) {
case 'layout-info':
case 'layer-info':
call.updateLayouts(eventData);
break;
case 'logo-info':
call.updateLogo(eventData);
break;
case 'caption-info':
call.handleCaptionInfo(eventData);
break;
}
};
const _buildCall = (session, params, attach, nodeId) => {
const call = new Call(session, {
id: params.callID,
remoteSdp: params.sdp,
destinationNumber: params.callee_id_number,
remoteCallerName: params.caller_id_name,
remoteCallerNumber: params.caller_id_number,
callerName: params.callee_id_name,
callerNumber: params.callee_id_number,
attach,
secondSource: /;second-source$/.test(params.callee_id_number),
screenShare: /;screen$/.test(params.callee_id_number),
shakenCheck: params.shaken_check || '',
shakenResult: params.shaken_result || '',
});
const hasAudioLine = params.sdp.indexOf('m=audio') !== -1;
if (!hasAudioLine) {
call.options.audio = false;
call.options.micId = null;
call.options.micLabel = null;
}
const hasVideoLine = params.sdp.indexOf('m=video') !== -1;
if (!hasVideoLine) {
call.options.video = false;
call.options.camId = null;
call.options.camLabel = null;
}
call.nodeId = nodeId;
call.isDirect = checkIsDirectCall(params);
return call;
};
export default (session, msg) => {
const { id, method, nodeId, params } = msg;
const { callID, eventChannel, eventType } = params;
if (eventType === 'channelPvtData') {
params.pvtData.nodeId = nodeId;
return _handlePvtEvent(session, params.pvtData);
}
if (eventChannel === session.sessionid) {
return _handleSessionEvent(session, params.eventData);
}
if (callID && session.calls.hasOwnProperty(callID)) {
trigger(callID, params, method);
if (method !== VertoMethod.Attach) {
const msg = new Result(id, method);
msg.targetNodeId = nodeId;
session.execute(msg);
}
this.session.execute(msg);
return;
}
handleMessage(msg) {
const { session } = this;
const { id, method, params } = msg;
const { callID, eventChannel, eventType } = params;
const attach = method === VertoMethod.Attach;
if (eventType === 'channelPvtData') {
return this._handlePvtEvent(params.pvtData);
const attach = method === VertoMethod.Attach;
switch (method) {
case VertoMethod.Ping:
const msg = new Result(id, method);
msg.targetNodeId = nodeId;
return session.execute(msg);
case VertoMethod.Punt:
session.purge();
return session.disconnect();
case VertoMethod.Invite: {
const call = _buildCall(session, params, attach, nodeId);
call.setState(State.Ringing);
const msg = new Result(id, method);
msg.targetNodeId = nodeId;
return session.execute(msg);
}
if (callID && session.calls.hasOwnProperty(callID)) {
if (attach) {
session.calls[callID].hangup({}, false);
}
else {
session.calls[callID].handleMessage(msg);
this._ack(id, method);
case VertoMethod.Attach: {
const call = _buildCall(session, params, attach, nodeId);
return trigger(call.id, params, method);
}
case VertoMethod.Event:
case 'webrtc.event': {
const { subscribedChannel } = params;
if (subscribedChannel && trigger(session.relayProtocol, params, subscribedChannel)) {
return;
}
}
const _buildCall = () => {
const call = new Call(session, {
id: callID,
remoteSdp: params.sdp,
destinationNumber: params.callee_id_number,
remoteCallerName: params.caller_id_name,
remoteCallerNumber: params.caller_id_number,
callerName: params.callee_id_name,
callerNumber: params.callee_id_number,
attach,
secondSource: /;second-source$/.test(params.callee_id_number),
screenShare: /;screen$/.test(params.callee_id_number),
});
call.nodeId = this.nodeId;
return call;
};
switch (method) {
case VertoMethod.Punt:
session.disconnect();
break;
case VertoMethod.Invite: {
const call = _buildCall();
call.setState(State.Ringing);
this._ack(id, method);
break;
}
case VertoMethod.Attach: {
const call = _buildCall();
if (this.session.autoRecoverCalls) {
call.answer();
}
else {
call.setState(State.Recovering);
}
call.handleMessage(msg);
break;
}
case VertoMethod.Event:
case 'webrtc.event':
if (!eventChannel) {
logger.error('Verto received an unknown event:', params);
if (eventChannel) {
const channelType = eventChannel.split('.')[0];
const global = trigger(session.relayProtocol, params, channelType);
const specific = trigger(session.relayProtocol, params, eventChannel);
if (global || specific) {
return;
}
const protocol = session.relayProtocol;
const firstValue = eventChannel.split('.')[0];
if (session._existsSubscription(protocol, eventChannel)) {
trigger(protocol, params, eventChannel);
}
else if (eventChannel === session.sessionid) {
this._handleSessionEvent(params.eventData);
}
else if (session._existsSubscription(protocol, firstValue)) {
trigger(protocol, params, firstValue);
}
else if (session.calls.hasOwnProperty(eventChannel)) {
session.calls[eventChannel].handleMessage(msg);
}
else {
trigger(SwEvent.Notification, params, session.uuid);
}
break;
case VertoMethod.Info:
params.type = NOTIFICATION_TYPE.generic;
trigger(SwEvent.Notification, params, session.uuid);
break;
case VertoMethod.ClientReady:
params.type = NOTIFICATION_TYPE.vertoClientReady;
trigger(SwEvent.Notification, params, session.uuid);
break;
default:
logger.warn('Verto message unknown method:', msg);
}
}
_retrieveCallId(packet, laChannel) {
const callIds = Object.keys(this.session.calls);
if (packet.action === 'bootObj') {
const me = packet.data.find((pr) => callIds.includes(pr[0]));
if (me instanceof Array) {
return me[0];
}
params.type = Notification.Generic;
return trigger(SwEvent.Notification, params, session.uuid);
}
else {
return callIds.find((id) => this.session.calls[id].channels.includes(laChannel));
}
case VertoMethod.Info:
params.type = Notification.Generic;
return trigger(SwEvent.Notification, params, session.uuid);
case VertoMethod.ClientReady:
params.type = Notification.VertoClientReady;
return trigger(SwEvent.Notification, params, session.uuid);
case VertoMethod.Announce:
params.type = Notification.Announce;
return trigger(SwEvent.Notification, params, session.uuid);
default:
logger.debug('Unknown Verto method:', method, params);
params.type = method;
return trigger(SwEvent.Notification, params, session.uuid);
}
_handlePvtEvent(pvtData) {
return __awaiter(this, void 0, void 0, function* () {
const { session } = this;
const protocol = session.relayProtocol;
const { action, laChannel, laName, chatChannel, infoChannel, modChannel, conferenceMemberID, role, callID } = pvtData;
switch (action) {
case 'conference-liveArray-join': {
const _liveArrayBootstrap = () => {
session.vertoBroadcast({ nodeId: this.nodeId, channel: laChannel, data: { liveArray: { command: 'bootstrap', context: laChannel, name: laName } } });
};
const tmp = {
nodeId: this.nodeId,
channels: [laChannel],
handler: ({ data: packet }) => {
const id = callID || this._retrieveCallId(packet, laChannel);
if (id && session.calls.hasOwnProperty(id)) {
const call = session.calls[id];
call._addChannel(laChannel);
call.extension = laName;
call.handleConferenceUpdate(packet, pvtData)
.then(error => {
if (error === 'INVALID_PACKET') {
_liveArrayBootstrap();
}
});
}
}
};
const result = yield session.vertoSubscribe(tmp)
.catch(error => {
logger.error('liveArray subscription error:', error);
});
if (checkSubscribeResponse(result, laChannel)) {
_liveArrayBootstrap();
}
break;
}
case 'conference-liveArray-part': {
const call = session.calls[callID] || null;
if (call) {
const notification = { type: NOTIFICATION_TYPE.conferenceUpdate, action: ConferenceAction.Leave, call, conferenceName: laName, participantId: Number(conferenceMemberID), role };
if (!trigger(SwEvent.Notification, notification, call.id, false)) {
trigger(SwEvent.Notification, notification, session.uuid);
}
deRegister(SwEvent.Notification, null, call.id);
if (call.isMainCall === false) {
return call.destroy();
}
}
const channels = [laChannel, chatChannel, infoChannel, modChannel];
const { unsubscribedChannels = [] } = yield session.vertoUnsubscribe({ nodeId: this.nodeId, channels })
.catch(error => {
logger.error('liveArray unsubscribe error:', error);
});
if (call) {
call.channels = call.channels.filter(c => !unsubscribedChannels.includes(c));
call.destroy();
}
break;
}
}
});
}
_handleSessionEvent(eventData) {
switch (eventData.contentType) {
case 'layout-info':
case 'layer-info':
MCULayoutEventHandler(this.session, eventData);
break;
case 'logo-info': {
const notification = { type: NOTIFICATION_TYPE.conferenceUpdate, action: ConferenceAction.LogoInfo, logo: eventData.logoURL };
trigger(SwEvent.Notification, notification, this.session.uuid);
break;
}
}
}
}
export default VertoHandler;
};
import Relay from './src/SignalWire';
import Verto from './src/Verto';
import CantinaAuth from '../common/src/webrtc/CantinaAuth';
export declare const VERSION = "1.3.0-cantina.7";
export declare const VERSION = "1.3.0-cantina.8";
export { Relay, Verto, CantinaAuth };
export * from '../common/src/webrtc/deviceHelpers';
export * from '../common/src/util/interfaces';
export * from '../common/src/webrtc/interfaces';

@@ -5,4 +5,5 @@ import Relay from './src/SignalWire';

import CantinaAuth from '../common/src/webrtc/CantinaAuth';
export const VERSION = '1.3.0-cantina.7';
export const VERSION = '1.3.0-cantina.8';
setAgentName(`JavaScript SDK/${VERSION}`);
export { Relay, Verto, CantinaAuth };
export * from '../common/src/webrtc/deviceHelpers';
import BrowserSession from '../../common/src/BrowserSession';
import BaseMessage from '../../common/src/messages/BaseMessage';
import { CallOptions } from '../../common/src/webrtc/interfaces';
import Call from '../../common/src/webrtc/Call';
export default class SignalWire extends BrowserSession {
execute(message: BaseMessage): any;
newCall(options: CallOptions): Promise<Call>;
}

@@ -11,17 +11,4 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

import BrowserSession from '../../common/src/BrowserSession';
import { Execute } from '../../common/src/messages/Blade';
import BaseRequest from '../../common/src/messages/verto/BaseRequest';
import Call from '../../common/src/webrtc/Call';
export default class SignalWire extends BrowserSession {
execute(message) {
let msg = message;
if (message instanceof BaseRequest) {
const params = { message: message.request };
if (message.targetNodeId) {
params.node_id = message.targetNodeId;
}
msg = new Execute({ protocol: this.relayProtocol, method: 'message', params });
}
return super.execute(msg);
}
newCall(options) {

@@ -28,0 +15,0 @@ return __awaiter(this, void 0, void 0, function* () {

@@ -5,13 +5,18 @@ import BrowserSession from '../../common/src/BrowserSession';

import Call from '../../common/src/webrtc/Call';
export declare const VERTO_PROTOCOL = "verto-protocol";
import BaseMessage from '../../common/src/messages/BaseMessage';
export default class Verto extends BrowserSession {
relayProtocol: string;
timeoutErrorCode: number;
loginResponse: any;
moderator: boolean;
superuser: boolean;
validateOptions(): boolean;
newCall(options: CallOptions): Call;
broadcast(params: BroadcastParams): void;
broadcast(params: BroadcastParams): any;
subscribe(params: SubscribeParams): Promise<any>;
unsubscribe(params: SubscribeParams): Promise<any>;
ping(): any;
_wrapInExecute(message: BaseMessage): BaseMessage;
protected _onSocketOpen(): Promise<void>;
protected _onSocketMessage(msg: any): void;
}

@@ -11,9 +11,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

import BrowserSession from '../../common/src/BrowserSession';
import { Login } from '../../common/src/messages/Verto';
import { Login, Ping } from '../../common/src/messages/Verto';
import Call from '../../common/src/webrtc/Call';
import { SwEvent, SESSION_ID } from '../../common/src/util/constants';
import { SwEvent, SESSION_ID, VERTO_PROTOCOL } from '../../common/src/util/constants';
import { trigger } from '../../common/src/services/Handler';
import { localStorage } from '../../common/src/util/storage/';
import VertoHandler from '../../common/src/webrtc/VertoHandler';
export const VERTO_PROTOCOL = 'verto-protocol';
export default class Verto extends BrowserSession {

@@ -24,2 +23,5 @@ constructor() {

this.timeoutErrorCode = -329990;
this.loginResponse = {};
this.moderator = false;
this.superuser = false;
}

@@ -31,5 +33,2 @@ validateOptions() {

newCall(options) {
if (this._idle || !this.connected) {
throw new Error('Client not connected');
}
const { destinationNumber = null } = options;

@@ -52,2 +51,9 @@ if (!destinationNumber) {

}
ping() {
const msg = new Ping({ serno: Date.now() });
return this.execute(msg);
}
_wrapInExecute(message) {
return message;
}
_onSocketOpen() {

@@ -57,6 +63,2 @@ return __awaiter(this, void 0, void 0, function* () {

const { login, password, passwd, userVariables } = this.options;
if (this.sessionid) {
const sessidLogin = new Login(undefined, undefined, this.sessionid, undefined);
yield this.execute(sessidLogin).catch(() => null);
}
const msg = new Login(login, (password || passwd), this.sessionid, userVariables);

@@ -66,4 +68,9 @@ const response = yield this.execute(msg).catch(this._handleLoginError);

this._autoReconnect = true;
this.loginResponse = response;
this.moderator = response.moderator || false;
this.superuser = response.superuser || false;
this.sessionid = response.sessid;
localStorage.setItem(SESSION_ID, this.sessionid);
if (!this.incognito) {
localStorage.setItem(SESSION_ID, this.sessionid);
}
trigger(SwEvent.Ready, this, this.uuid);

@@ -74,5 +81,4 @@ }

_onSocketMessage(msg) {
const handler = new VertoHandler(this);
handler.handleMessage(msg);
VertoHandler(this, msg);
}
}
{
"name": "@signalwire/js",
"version": "1.3.0-cantina.7",
"version": "1.3.0-cantina.8",
"description": "Relay SDK for JavaScript to connect to SignalWire.",

@@ -21,3 +21,3 @@ "author": "SignalWire Team <open.source@signalwire.com>",

"tslint": "tslint -p tsconfig.json",
"test": "jest --forceExit --detectOpenHandles",
"test": "jest --no-cache --forceExit --detectOpenHandles",
"test:watch": "npm run test -- --watchAll",

@@ -61,4 +61,4 @@ "validate": "npm i && npm run tslint && npm run test && npm run clean-build",

"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
"webpack-dev-server": "^3.11.0"
}
}

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc