ZoomMtg.js

/* eslint valid-jsdoc: "error" */
/* eslint-env es6 */

/**
 * @file This is zoom WebSDK for web.
 * @copyright Zoom 2021
 * @version WebSDK1.9.6
 * @namespace ZoomMtg
 */

const ZoomMtg = {
  generateSignature,
  init,
  join,
  showInviteFunction,
  showCalloutFunction,
  showMeetingHeader,
  showRecordFunction,
  showJoinAudioFunction,
  showPureSharingContent,
  getAttendeeslist,
  getCurrentUser,
  callOut,
  inviteByPhone,
  inviteCRCDevice,
  cancelInviteCRCDevice,
  mute,
  muteAll,
  rename,
  expel,
  record,
  lockMeeting,
  leaveMeeting,
  endMeeting,
  successCallBack,
  errorCallBack,
  inMeetingServiceListener,
  reRender,
  putOnHold,
};


/**
 * @typedef errorCodes
 * @method errorCodes
 * @property {string} [0] - invoke function success
 * @property {string} [1] - invoke function error
 * @property {string} [2] - you must be init at first
 * @property {string} [403] - apac.errorcodes_offline
 * @property {string} [3000] - apac.errorcodes_web_has_in_progress
 * @property {string} [3003] - apac.errorcodes_not_host
 * @property {string} [3004] - apac.errorcodes_wrong_pass
 * @property {string} [3005] - apac.errorcodes_web_require_email
 * @property {string} [3008] - apac.errorcodes_not_start
 * @property {string} [3009] - apac.errorcodes_be_removed
 * @property {string} [3082] - apac.errorcodes_login_required
 * @property {string} [3110] - need check recaptcha
 * @property {string} [3051] - need zoom login
 * @property {string} [3052] - need zoom login with specific login
 * @property {string} [6024] - need sso login
 * @property {string} [3603] - apac.errorcodes_web_not_support_webclient
 * @property {string} [3604] - apac.errorcodes_web_should_support_webinar_with_latest_version
 * @property {string} [3606] - apac.errorcodes_web_not_support_registration_webinar
 * @property {string} [3608] - apac.errorcodes_web_not_support_tsp
 * @property {string} [3609] - apac.errorcodes_web_not_allow_start_webinar_from_web
 * @property {string} [3610] - apac.errorcodes_not_exist
 * @property {string} [3610] - apac.errorcodes_tk_expired
 * @property {string} [3620] - apac.errorcodes_denied_email
 * @property {string} [3630] - apac.errorcodes_not_support_simulive
 * @property {string} [3633] - apac.errorcodes_frequent_call
 * @property {string} [3701] - apac.errorcodes_web_not_support_webinar_pac
 * @property {string} [3702] - apac.errorcodes_web_host_not_exit
 * @property {string} [3703] - apac.errorcodes_web_invalid_id
 * @property {string} [3704] - apac.errorcodes_pac_api_wrong
 * @property {string} [3705] - apac.errorcodes_pac_signature_expired
 * @property {string} [3706] - apac.errorcodes_pac_mn_wrong
 * @property {string} [3707] - apac.errorcodes_pac_mn_not_fount
 * @property {string} [3708] - apac.errorcodes_pac_role_error
 * @property {string} [3709] - apac.errorcodes_pac_host_not_found
 * @property {string} [3710] - apac.errorcodes_pac_api_disabled
 * @property {string} [3711] - apac.errorcodes_pac_cant_host_other_mn
 * @property {string} [3712] - apac.errorcodes_pac_invalid_signature
 * @property {string} [3713] - apac.errorcodes_pac_no_permission
 * @property {string} [4000] - reconnecting meeting
 * @property {string} [4001] - disconnect meeting
 * @property {string} [4003] - apac.invalid_parameter
 */

/**
 * Success Callback
 * @callback successCallback
 * @memberof ZoomMtg
 * @param {Object} res - Response Object
 * @property {string} res.method - API Method
 * @property {boolean} res.status - Status of call
 * @property {int} res.errorCode - Error Code {@link errorCodes}
 * @property {string} res.errorMessage - Error message {@link errorCodes}
 * @property {Object} res.result - Response result object
 */

/**
 * Error Callback
 * @callback errorCallback
 * @memberof ZoomMtg
 * @param {Object} res - Response Object
 * @property {string} res.method - API Method
 * @property {boolean} res.status - Status of call
 * @property {int} res.errorCode - Error Code {@link errorCodes}
 * @property {string} res.errorMessage - Error message {@link errorCodes}
 * @property {Object} res.result - Response result object
 */

/**
 * change zoom default requirements lib resource
 * @memberof ZoomMtg
 * @method setZoomJSLib
 * @instance
 * @param {Object} params options
 * @param {string} [params.zoomJSLib='https://source.zoom.us/1.9.6/lib'] - default use ES5
 * @param {string} [params.zoomJSAVLib='/av'] - default build var
 * @param {string} [params.zoomJSLib='YouWebSite/node_modules/@zoomus/websdk/dist/lib'] - default use ES6 import feature
 * @param {string} [params.zoomJSAVLib='/av'] - default build var
 * @example
 *
 * ZoomMtg.setZoomJSLib('https://source.zoom.us/1.9.6/lib', '/av');
 * AVFiles = {
    audioWorkerPath: `${zoomJSLib}${zoomJSAVLib}/${jsmediaVersion}_js_audio_process.min.js`,
    audioWorkletPath: `${zoomJSLib}${zoomJSAVLib}/${jsmediaVersion}_js_audio_worklet.min.js`,
    videoWorkerPath: `${zoomJSLib}${zoomJSAVLib}/${jsmediaVersion}_video_s.min.js`,
    videoMtWorkerPath: `${zoomJSLib}${zoomJSAVLib}/${jsmediaVersion}_video_m.min.js`,
    sharingWorkerPath: `${zoomJSLib}${zoomJSAVLib}/${jsmediaVersion}_sharing_s.min.js`,
    sharingMtWorkerPath: `${zoomJSLib}${zoomJSAVLib}/${jsmediaVersion}_sharing_m.min.js`,
    videoSIMDWorkerPath: `${zoomJSLib}${zoomJSAVLib}/${jsmediaVersion}_video_simd.min.js`,
    sharingSIMDWorkerPath: `${zoomJSLib}${zoomJSAVLib}/${jsmediaVersion}_sharing_simd.min.js`,
};


WasmFiles = {
 encode: `${zoomJSLib}${zoomJSAVLib}/audio.encode.wasm`,
 decode: `${zoomJSLib}${zoomJSAVLib}/video.decode.wasm`,
 decodeMt: `${zoomJSLib}${zoomJSAVLib}/video.mt.wasm`,
 decodeSimd: `${zoomJSLib}${zoomJSAVLib}/video.simd.wasm`,
};
 */

/**
 * preload wasm file if wasm download error, the 2AV feature don't work
 * wasm file(big) to browser cache, reduce customer download those file time and improve joining experience
 * @memberof ZoomMtg
 * @method preLoadWasm
 * @instance
 * @example
 * ZoomMtg.preLoadWasm();
 * // avMediaVersion can't change, every websdk version has a specific avMediaVersion
 * // pre load wasm success: ${zoomJSLib}${zoomJSAVLib}/av/{avMediaVersion}_sharing.wasm
 * // pre load wasm success: ${zoomJSLib}${zoomJSAVLib}/av/{avMediaVersion}_audio.encode.wasm
 * // pre load wasm success: ${zoomJSLib}${zoomJSAVLib}/av/{avMediaVersion}_video.decode.wasm
 */

/**
 * add script to download requirements js file and node to body
 * @memberof ZoomMtg
 * @method prepareWebSDK
 * @instance
 * @example
 * ZoomMtg.prepareWebSDK();
 *
 * // 1. add script to download requirements js file
 * // for IE
 * // <script type="text/javascript" src="${zoomJSLib}${zoomJSAVLib}/av/../{avMediaVersion}_webim.min.js"></script>
 * // <script type="text/javascript" src="${zoomJSLib}${zoomJSAVLib}/av/{avMediaVersion}_js_media_ie.min.js"></script>
 * // for No IE
 * // <script type="text/javascript" src="${zoomJSLib}${zoomJSAVLib}/av/../{avMediaVersion}_webim.min.js"></script>
 * // <script type="text/javascript" src="${zoomJSLib}${zoomJSAVLib}/av/{avMediaVersion}_js_media.min.js"></script>


 * // 2. add a node which WebSDK use
 * // <div id="zmmtg-root">
 * //   <div data-reactroot="" class="meeting-app"></div>
 * // </div>
 * // react modal auto generation.
 * // <div class="ReactModalPortal"></div>
 *
 */

/**
 * A quick test way to generate signature, get an api {@link https://marketplace.zoom.us/docs/sdk/native-sdks/web/essential/signature}
 * introduce get API https://www.visibility.one/support/zoom-api-how-to-get-your-api-from-the-zoom-marketplace
 * backe-end to genarate signature go to see {@link generate_signature} in php
 * @memberof ZoomMtg
 * @instance
 * @method generateSignature
 * @param {Object} params options
 * @param {string} params.apiKey - api key
 * @param {string} params.apiSecret - api secret
 * @param {string} params.meetingNumber - meeting number
 * @param {number} params.role - 1 is host, 0 is attendee, webinar just support 0
 * @return {string} return signature
 * @example
 *
 *
 * //source code generateSignature
import * as base64JS from 'js-base64';
import * as hmacSha256 from 'crypto-js/hmac-sha256';
import * as encBase64 from 'crypto-js/enc-base64';

function generateSignature(data) {
    let signature = '';
    // Prevent time sync issue between client signature generation and zoom
    const ts = new Date().getTime() - 30000;
    try {
        const msg = base64JS.Base64.encode(data.apiKey + data.meetingNumber + ts + data.role);
        const hash = hmacSha256.default(msg, data.apiSecret);
        signature = base64JS.Base64.encodeURI(`${data.apiKey}.${data.meetingNumber}.${ts}.${data.role}.${encBase64.stringify(hash)}`);
    } catch (e) {
         console.log('error')
    }
    return signature;
}
 */

/**
 * check zoom WebSDK features for customer's browser
 * @memberof ZoomMtg
 * @method checkSystemRequirements
 * @param {Boolean} [print=true] - whether console log check info
 * @return {Object} return check result, return false when check fail
 * @instance
 * @example
 * ZoomMtg.checkSystemRequirements()
 *
 * //ie 9 example check fail
 * false
 *
 * //chrome example check success
{
"browserInfo": "Chrome/87.0.4280.88",
"browserName": "Chrome",
"browserVersion": "87.0.4280.88",
"features": ["viewSharing", "computerAudio", "computerVideo", "callIn", "callOut", "chat", "closedCaption", "QA", "POLLING", "BREAKOUT"]
}
 *
 */

/**
 * get WebSDK version
 * @memberof ZoomMtg
 * @method getWebSDKVersion
 * @return {Array} return WebSDK version number. old getJSSDKVersion will remove very soon
 * @instance
 * @example
 * ZoomMtg.getWebSDKVersion()
 * @example
    ["1.9.6", "1.9.6", 6331]
 */

/**
 * Init Zoom Meeting
 * @memberof ZoomMtg
 * @method init
 * @instance
 * @param {Object} params options
 * @param {Object} params.loginWindow options
 * @param {boolean} [params.debug=false] - Turn on debug mode can print log in browser console log
 * @param {string} params.leaveUrl - required, Post message page url after leave meeting, like “http://www.zoom.us”
 * @param {string} [params.webEndpoint] - web domain option for PSO ENV, contract with zoom PSO supporter
 * @param {boolean} [params.showMeetingHeader=true] - Show or hide the meeting header, includes meeting number and topic
 * @param {boolean} [params.disableInvite=false] - Enable or disable invite function.
 * @param {boolean} [params.disableCallOut=false] - Enable or disable call out function.
 * @param {boolean} [params.disableRecord=false] - Enable or disable record function.
 * @param {boolean} [params.disableJoinAudio=false] - Enable or disable join audio function.
 * @param {boolean} [params.audioPanelAlwaysOpen=false] - Set the default state of the audio panel on join.
 * @param {boolean} [params.isSupportAV=true] - Enable or disable if you want use audio and video feature.
 * @param {boolean} [params.isSupportChat=true] - Enable or disable if you want use chat feature.
 * @param {boolean} [params.isSupportQA=true] - Enable or disable if you want use Webinar Q&A feature.
 * @param {boolean} [params.isSupportCC=true] - Enable or disable if you want use Meeting Closed Caption feature.
 * @param {boolean} [params.isSupportPolling=true] - Enable or disable if you want use Meeting Polling feature.
 * @param {boolean} [params.isSupportBreakout=true] - Enable or disable if you want use Meeting Breakout Room feature.
 * @param {boolean} [params.screenShare=true] - Enable or disable if you want use browser feature(only chrome).
 * @param {boolean} [params.rwcBackup=''] - rwc domain, if set enable multi-rwc feature
 * @param {boolean} [params.videoDrag=true] - Enable drag video tile
 * @param {boolean} [params.sharingMode='both'] - 'fit' - disable sharing "origin size"
 * @param {boolean} [params.videoHeader=true] - Enable show video tile header
 * @param {boolean} [params.isLockBottom=true] - alway show footer or auto hide footer
 * @param {boolean} [params.isSupportNonverbal=true] - Enable/Disable Noverbal feedback feature
 * @param {boolean} [params.isShowJoiningErrorDialog=true] - Enable/Disable Join error popup dialog when join meeting fail
 * @param {boolean} [params.disablePreview=false] - Enable/Disable Audio and Video Preview
 * @param {boolean} [params.disableCORP=true] - Enable/Disable web isolation mode
 * @param {string} [params.inviteUrlFormat=''] - hide: hide invite url, or customer invite formate "https://your.com/?j={0}pwd={1}"
 * @param {int} [params.loginWindow.width=400] - Login subWindow width
 * @param {int} [params.loginWindow.height=380] - Login subWindow height
 * @param {boolean} [params.disableVoIP=false] - Enable/Disable VoIP feature
 * @param {boolean} [params.disableReport=false] - Enable/Disable Report feature
 * @param {array} [params.meetingInfo=['topic','host','mn','pwd','telPwd','invite','participant','dc', 'enctype', 'report']] - choice which meeting info want to show
 * @param {ZoomMtg.successCallback} [params.success] - Call back function on success
 * @param {ZoomMtg.errorCallback} [params.error] - Call back function on error
//  * @gifs gif1;gif2 - / ;en/1.5.1/images/tenor.gif;http://localhost:9999/images/tenor.gif
 * @example
    ZoomMtg.init({
    debug: true, //optional
    leaveUrl: 'http://www.zoom.us', //required
    webEndpoint: 'PSO web domain', // PSO option
    showMeetingHeader: false, //option
    disableInvite: false, //optional
    disableCallOut: false, //optional
    disableRecord: false, //optional
    disableJoinAudio: false, //optional
    audioPanelAlwaysOpen: true, //optional
    showPureSharingContent: false, //optional
    isSupportAV: true, //optional,
    isSupportChat: true, //optional,
    isSupportQA: true, //optional,
    isSupportPolling: true, //optional
    isSupportBreakout: true, //optional
    isSupportCC: true, //optional,
    screenShare: true, //optional,
    rwcBackup: '', //optional,
    videoDrag: true, //optional,
    sharingMode: 'both', //optional,
    videoHeader: true, //optional,
    isLockBottom: true, // optional,
    isSupportNonverbal: true, // optional,
    isShowJoiningErrorDialog: true, // optional,
    disablePreview: false, // optional
    disableCORP: true, // optional
    inviteUrlFormat: '', // optional
    loginWindow: {  // optional,
      width: 400,
      height: 380
    },
    meetingInfo: [ // optional
      'topic',
      'host',
      'mn',
      'pwd',
      'telPwd',
      'invite',
      'participant',
      'dc',
      'enctype',
      'report'
    ],
    disableVoIP: false, // optional
    disableReport: false, // optional
    });
 */

/**
 * @memberof ZoomMtg
 * @method join
 * @instance
 * @param {Object} params options
 * @param {int} params.meetingNumber - required
 * @param {string} params.userName - required
 * @param {string} params.userEmail - Webinar required
 * @param {string} params.passWord - required
 * @param {string} params.signature - required
 * @param {string} params.apiKey - required
 * @param {string} params.customeKey
 * @param {string} params.tk
 * @param {ZoomMtg.successCallback} [params.success] - Call back function on success
 * @param {ZoomMtg.errorCallback} [params.error] - Call back function on error
 * @example
 * ZoomMtg.join({
    meetingNumber: 123456789,
    userName: 'User name',
    userEmail: '',
    passWord: '',
    apiKey: 'API_KEY',
    signature: 'SIGNATURE',
    success: function(res){console.log(res)},
    error: function(res){console.log(res)}
 });
 */

/**
 * Show or hide invite function
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {boolean} [params.show=true] - default true, required
 * @method showInviteFunction
 * @example
 * ZoomMtg.showInviteFunction({
    show: true
});
 */

/**
 * Show/Hide meeting header
 * @method showMeetingHeader
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {boolean} [params.show=true] - default true, required
 * @example
 * ZoomMtg.showMeetingHeader({
	show: false
 });
 */

/**
 * Show/Hide record function
 * @method showRecordFunction
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {boolean} [params.show=true] - default true, required
 * @example
 * ZoomMtg.showRecordFunction({
	show: false
 });
 */

/**
 * Show/Hide call out function
 * @method showCalloutFunction
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {boolean} [params.show=true] - default true, required
 * @example
 * ZoomMtg.showCalloutFunction({
	show: false
 });
 */

/**
 * Show/Hide join audio function
 * @method showJoinAudioFunction
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {boolean} [params.show=true] - default true, required
 * @example
 * ZoomMtg.showJoinAudioFunction({
	show: false
 });
 */

/**
 * Will not cover sharing content when set show as true
 * @method showPureSharingContent
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {boolean} [params.show=true] - default true, required
 * @example
 * ZoomMtg.showPureSharingContent({
	show: false
 });
 */

/**
 * Get current attendees list, inde 0 is current user
 * @method getAttendeeslist
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @example
 * only support meeting
 * ZoomMtg.getAttendeeslist({});
 */

 /**
 * Get Breakout Room list and attendees
 * @method getBreakoutRoomList
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @example
 * only support meeting
 * ZoomMtg.getBreakoutRoomList({});
 */

/**
 * Get current user
 * @method getCurrentUser
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @example
 * ZoomMtg.getCurrentUser({});
 */

/**
 * Get current user
 * @method getCurrentMeetingInfo
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @example
 * ZoomMtg.getCurrentMeetingInfo({});
 */

/**
 * In meeting event
 * @method inMeetingServiceListener
 * @memberof ZoomMtg
 * @instance
 * @param {string} event event name
 * @param {function} callback callback function
 * @example
 * only support meeting
 * ZoomMtg.inMeetingServiceListener('onUserJoin', function (data) {
    console.log(data);
  });

  only support meeting
  ZoomMtg.inMeetingServiceListener('onUserLeave', function (data) {
    console.log(data);
  });

  ZoomMtg.inMeetingServiceListener('onUserIsInWaitingRoom', function (data) {
    console.log(data);
  });

  ZoomMtg.inMeetingServiceListener('onMeetingStatus', function (data) {
    // {status: 1(connecting), 2(connected), 3(disconnected), 4(reconnecting)}
    console.log(data);
  });
 */


/**
 * The method will invite yourself to join meeting by phone
 * @method callOut
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {boolean} params.phoneNumber - call out number
 * @example
 * ZoomMtg.callOut({
	phoneNumber: '+1800...'
 });
 */


/**
 * Invite by phone
 * @method inviteByPhone
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {string} params.phoneNumber - phone number
 * @param {string} params.userName - username
 * @example
ZoomMtg.inviteByPhone({
    phoneNumber: '+11111111',
    userName: 'username'
});
 */

/**
 * Invite CRC Device
 * @method inviteCRCDevice
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {string} params.ip - CRC device ip
 * @param {int} params.type - device type
 * @example
ZoomMtg.inviteCRCDevice({
    ip: '10.100.80.98',
    type: 1
});
 */


/**
 * mute attendee
 * @method mute
 * @memberof ZoomMtg
 * @instance
 * @param {Object} params
 * @param {int} params.userId - userId
 * @param {boolean} params.mute - true or false
 * @example
 * ZoomMtg.mute({
    userId: 16797696,
    mute: true
});
 */

/**
 * mute/unmute all attendee, the role must bee has this proviliage
 * @method muteAll
 * @instance
 * @memberof ZoomMtg
 * @param {Object} params
 * @param {boolean} params.muteAll - true or false
 * @example
 * ZoomMtg.muteAll({
    muteAll: true
});
 */

/**
 * rename attendee name, the role must bee has this proviliage
 * userId and oldName must bee right, otherwise you can't modify success
 * @method rename
 * @instance
 * @memberof ZoomMtg
 * @param {Object} params
 * @param {int} params.userId - userId
 * @param {string} params.oldName - ole name
 * @param {string} params.newName - new name
 * @example
ZoomMtg.rename({
    userId: 123456,
    oldName: 'ole name',
    newName: 'new name'
});
 */

/**
 * kickoff attendee, must have proliliage
 * @method expel
 * @instance
 * @memberof ZoomMtg
 * @param {Object} params
 * @param {int} params.userId - expel user id
 * @example
 * ZoomMtg.expel({
    userId: 123456
});
*/

/**
 * record/disrecord meeting, host only
 * @method record
 * @instance
 * @memberof ZoomMtg
 * @param {Object} params
 * @param {boolean} params.record - true or false
 * @example
 * ZoomMtg.record({
    record: true
});
*/

/**
 * lock/unlock meeting, others can't join this meeting unless unlock meeting
 * @method lockMeeting
 * @instance
 * @memberof ZoomMtg
 * @param {Object} params
 * @param {boolean} params.lockMeeting - true=lock meeting or false=unlock
 * @example
 * ZoomMtg.lockMeeting({
    lockMeeting: true
});
*/

/**
 * leave meeting, if host leave, the meeting will end.
 * @method leaveMeeting
 * @instance
 * @memberof ZoomMtg
 * @param {Object} params
 * @example
 * ZoomMtg.leaveMeeting({});
 */

/**
 * end meeting
 * @method endMeeting
 * @instance
 * @memberof ZoomMtg
 * @param {Object} params
 * @example
 * ZoomMtg.endMeeting({});
 */

/**
 * allow attendee to joining meeting
 * @method  putOnHold
 * @instance
 * @memberof ZoomMtg
 * @param {Object} params
 * @param {int} params.userId - user id
 * @param {boolean} params.hold - true= put attendee to waiting room. false=let him join meeting
 * @example
 * ZoomMtg.putOnHold({
    userId: 123456,
    hold: true
});
*/

// $.i18n.reload(langArray[langI]);
// ZoomMtg.reRender({"lang": langArray[langI]});

module.exports = ZoomMtg;