Source: ZegoExpressEngine.js


let ZegoExpressNodeNativePath = "";
let os = require("os");
if (os.platform() === "win32") {
    if (process.arch === 'x64') {
        ZegoExpressNodeNativePath = `./x64/ZegoExpressNodeNative`;
    }
    else {
        ZegoExpressNodeNativePath = `./x86/ZegoExpressNodeNative`;
    }
}
else if (os.platform() === "darwin") {
    ZegoExpressNodeNativePath = "./mac/ZegoExpressNodeNative";
}
else {
    throw ("Platform not supported")
}

const EventEmitter = require('events').EventEmitter;
const ZegoNativeSDK = require(ZegoExpressNodeNativePath);
const PackageJson = require('./package.json');
const WebGLRender = require('./ZegoExpressWebgl');
const ZegoMediaPlayer = require('./ZegoExpressMediaPlayer');
const {ZegoPublishChannel, ZegoViewMode, ZegoPlayerVideoLayer, ZegoCapturePipelineScaleMode} = require('./ZegoExpressDefines');

/**
 * ZegoExpressEngine
 */
class ZegoExpressEngine extends EventEmitter {

    /**
     * 初始化引擎。
     *
     * 在调用其他函数前需要先创建并初始化引擎。
     * @param {ZegoEngineProfile} profile - 用来创建引擎的基础配置信息。
     */
    initWithProfile(profile){
        let tsfn = this.callEmit.bind(this);
        const that = this;
        that.appID = profile.appID;

        //get electron sdk version
        var SdkVersion = this.getVersion();

        return new Promise(function (resolve, reject) {
            that.ZegoNativeInstance = ZegoNativeSDK.CreateEngineWithProfile({ profile, tsfn, SdkVersion });
            if (that.ZegoNativeInstance === undefined) {
                reject("Zego Express init failed");
            }
            else {
                that.VideoViewManager = {
                    localGLRenders: [],
                    remoteGLRenders: []
                };
                that.mediaPlayers = [];
                console.log("Zego Express init succeed");
                resolve();
            };
        });
    }

    /**
     * 反初始化引擎。
     *
     * 用于释放 SDK 使用的资源。
     */
    uninit(){
        const that = this;
        return new Promise(function(resolve, reject){
            ZegoNativeSDK.DestroyEngine();
            that.ZegoNativeInstance = null;
            that.VideoViewManager = null;
            that.mediaPlayers = null;
            that.removeAllListeners();
            console.log("Zego Express uninited");
            resolve();
        });
    }

    /**
     * 设置引擎进阶配置。
     *
     * 详情描述:用于开启进阶功能。
     * 调用时机:不同的配置有不同的调用时机要求,详情可咨询 ZEGO 技术支持。
     * 使用限制:无。
     * @param {ZegoEngineConfig} config - 引擎进阶配置
     */
    setEngineConfig(config){
        ZegoNativeSDK.SetEngineConfig({ config });
    }


    /**
     * 获取 SDK 版本号。
     *
     * 详情描述:在 SDK 在运行过程中若遇到异常,可将问题、日志等信息提交 ZEGO 技术人员定位与排障。开发者也可通过该 API 收集当前 SDK 版本信息,便于 App 运营统计以及关联问题。
     * 调用时机:任意时刻。
     * 使用限制:无。
     * 注意事项:无。
     * @return {string} - SDK 版本号。
     */
    getVersion(){
        return PackageJson.version;
    }

    /**
     * 上传日志到 ZEGO 服务器。
     *
     * 详情描述:默认情况下,SDK 会在 App 默认目录创建日志文件并打印,每个日志文件默认最大 5MB,三个日志文件循环覆盖写入。当调用此函数时 SDK 会自动将日志文件打包并上传到 ZEGO 服务器。
     * 业务场景:开发者可在 App 提供业务上的“反馈”渠道,当用户反馈的问题属于 ZEGO SDK 时,可调用此函数将 SDK 的本地日志信息上传,并联系 ZEGO 技术支持协助定位用户问题。
     * 调用时机:在 [initWithProfile/init] 后。
     * 使用限制:10分钟内如果反复调用此接口,只有最后一次调用生效。
     * 注意事项:在调用本接口上传日志后,如果过快的调用 [uninit] 或 退出 App,则可能存在失败的情况。建议等待几秒,等收到上传成功回调后,再调用 [uninit] 或 退出 App。
     */
    uploadLog(){
        this.ZegoNativeInstance.uploadLog({});
    }
    /**
     * 【已废弃】设置调试详细信息开关以及语言
     *
     * 此函数在版本 0.23.0 及以后已废弃,请使用 [setEngineConfig] 函数设置高级配置属性advancedConfig来实现原来的功能。
     * 默认开启且调试信息的语言为英文。
     * @param {boolean} enable - 详细调试信息开关
     * @param {ZegoLanguage} language - 调试信息语种
     * @deprecated 此函数在版本 0.23.0 以后已废弃,请使用 [setEngineConfig] 函数设置高级配置属性 advancedConfig 来实现原来的功能。
     */
    setDebugVerbose(enable, language){
        this.ZegoNativeInstance.setDebugVerbose({enable, language});
    }
    
    isConsolePrintDebugInfo = false;
    /**
     * 打开或关闭控制台调试
     * 
     * @param {boolean} enable - 详细的调试信息开关
     */
     enableConsolePrintDebugInfo(enable) {
         this.isConsolePrintDebugInfo = enable;
     }
     
     /**
     * 调用 RTC 实验性 API
     *
     * ZEGO通过此API在RTC业务中提供一些技术预览或特殊自定义功能。如果您需要获取使用功能或详细信息,请咨询ZEGO技术支持。
     * @param {string} params - 需要以 JSON 字符串的形式传入参数.
     * @return {string} - 返回 JSON 字符串格式的参数.
     */
    callExperimentalAPI(params){
        return this.ZegoNativeInstance.callExperimentalAPI({params});
    }

    /**
     * 使用配置进阶属性的方式登录房间,推拉流前必须登录房间。
     *
     * 详情描述:SDK 用"房间"概念来组织用户,用户必须首先登录某个房间,才能进行一系列关键操作,比如推流 [startPublishingStream]、拉流[startPlayingStream]、收发广播消息 [sendBroadcastMessage] 等。为了防止 App 被恶意用户模拟登录,可以在登录房间之前加上鉴权验证,即 [config] 参数传入的 ZegoRoomConfig 对象中的 [token] 参数。
     * 业务场景:在同一个房间内用户可以进行直播、音视频通话等。
     * 调用时机:在 [initWithProfile/init] 初始化 SDK 之后调用该函数。
     * 使用限制:同一房间登录接口的调用频率 (QPS) 有一定限制,详情查阅 https://doc-zh.zego.im/article/7581 或联系 ZEGO 技术支持。
     * 注意事项:1. 使用不同 appID 的 App 不能互通,测试环境和正式环境不能互通。2. SDK 支持拉相同 appID 下非同一个房间的流,即跨房间拉流。由于 SDK 的房间信令的相关回调通知是以相同房间为单位,当开发者想要跨房间拉流时,开发者需自行维护相关的消息及信令通知。3. 强烈建议 userID 与业务 APP 的用户 ID 一一对应,即一个 userID 与一个真实用户是固定且唯一的,而不应该是以随机的 userID 的方式传给 SDK 的方式。因为唯一且固定的 userID 可以让 ZEGO 技术人员快速定位线上问题。4. 首次因网络原因登陆失败或者房间断开连接之后,SDK 重连默认时间为 20min。5. 当用户已成功登录房间后,如果应用异常退出,在重启应用后,开发者需先调用 [logoutRoom] 接口退出房间,再调用 [loginRoom] 接口重新登录房间。
     * 隐私保护申明:请勿在此接口填写用户敏感信息,包括但不限于手机号、身份证号、护照编号、真实姓名等。
     * 相关回调:1. 当用户开始登录房间、登录房间成功或登录房间失败后,将会触发 [onRoomStateUpdate] 回调通知开发者当前用户连接房间的状态。2. 登录同一个房间的不同用户可以得到以相同房间为单位的房间信令通知(例如:[onRoomUserUpdate], [onRoomStreamUpdate] 等),一个房间内的用户收不到另一个房间房间信令的通知。3. 如果由于网络质量原因导致网络临时中断,SDK 内部会自动进行重连。可通过监听 [onRoomStateUpdate] 回调获取本端当前房间连接状态的变化情况,同时同房间其他用户会接收到 [onRoomUserUpdate] 回调通知。详情请参考 https://doc-zh.zego.im/article/10644。4. 一个房间发的消息(例如 [setStreamExtraInfo], [sendBroadcastMessage], [sendBarrageMessage], [sendCustomCommand] 等)在别的房间无法收到(例如 [onRoomStreamExtraInfoUpdate], [onIMRecvBroadcastMessage], [onIMRecvBarrageMessage], [onIMRecvCustomCommand] 等),目前 ZegoExpressEngine 未提供跨房间消息的能力。开发者可以集成 IM 的 SDK 来实现。
     * 相关接口:1. 可调用 [logoutRoom] 退出登录,如果没有退出登录而重复调用登录接口(roomID 和 user 保持相同的情况下),控制台会报错,打印错误码 1002001。2. 如果需要登录多个房间,请在创建引擎前通过 [ZegoRoomMode] 选择多房间模式,然后调用 [loginRoom] 接口登录多房间。3. 调用 [destroyEngine] 也会使用户自动退出登录。
  
  
     * @param {string} roomID - 房间 ID,最大长度为 128 字节的字符串。仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'.
     * @param {ZegoUser} user - 用户对象实例,配置用户 ID、用户名。 注意用户 ID 需要在相同的 appID 下全局唯一,否则会出现后登陆的用户踢掉先登陆的用户的情况。
     * @param {ZegoRoomConfig} config - 房间进阶配置。
     */
    loginRoom(roomID, user, config = { maxMemberCount:0, isUserStatusNotify: false, token:'' }){
        config = Object.assign({ maxMemberCount:0, isUserStatusNotify: false, token:'' }, config);
        this.ZegoNativeInstance.loginRoom({roomID, user, config});
    }
    
    /**
     * 【已废弃】登录多房间。
     *
     * 此方法在版本 0.24.1 以后已废弃,若需实现多房间功能,请先在引擎初始化之前调用 [setRoomMode] 函数设置多房间模式,再使用 [loginRoom] 登录多房间,如果调用 [loginRoom] 函数登录多房间,请确保传入相同的用户信息。
     * 必须先调用 [loginRoom] 函数成功登录主房间后,才可以调用此函数登录多房间。
     * 目前支持同时登录 1 个主房间和 1 个多房间。
     * 退出登录时也必须先登出多房间后才能登出主房间。
     * 用户只能在主房间中推流,但可以同时在主房间和多房间中拉流,并且可以正常收到每个房间中的信令及回调。
     * 多房间的优点主要在于,可以在不离开当前主房间的基础上,加入另一个房间,接收另一房间的信令及回调,播放另一个房间的音视频流。
     * 为了防止 App 被恶意用户模拟登录,可以在登录多房间之前加上鉴权验证,即 [config] 参数传入的 ZegoRoomConfig 对象中的 [token] 参数。
     * 登录同一个房间的不同用户可以得到以相同房间为单位的房间信令通知(例如:[onRoomUserUpdate], [onRoomStreamUpdate] 等),一个房间内的用户收不到另一个房间房间信令的通知。
     * 一个房间发的消息(例如 [setStreamExtraInfo], [sendBroadcastMessage], [sendBarrageMessage], [sendCustomCommand] 等)在别的房间无法收到(例如 [onRoomStreamExtraInfoUpdate], [onIMRecvBroadcastMessage], [onIMRecvBarrageMessage], [onIMRecvCustomCommand] 等),目前 SDK 未提供跨房间消息的能力。开发者可以集成第三方 IM 的 SDK 来实现。
     * SDK 支持拉相同 appID 下非同一个房间的流,即跨房间拉流。由于 SDK 的房间信令的相关回调通知是以相同房间为单位,当开发者想要跨房间拉流时,开发者需自行维护相关的消息及信令通知。
     * 如果由于网络质量原因导致网络临时中断,SDK 内部会自动进行重连。可通过监听 [onRoomStateUpdate] 回调获取本端当前房间连接状态的变化情况,同时同房间其他用户会接收到 [onRoomUserUpdate] 回调通知。
     * @param {string} roomID - 房间 ID,最大长度为 128 字节的字符串。仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'.
     * @param {ZegoRoomConfig} config - 房间进阶配置。
     * @deprecated 此方法在版本 0.24.1 以后已废弃,若需实现多房间功能,请先在引擎初始化之前调用 [setRoomMode] 函数设置多房间模式,再使用 [loginRoom] 登录多房间,如果调用 [loginRoom] 函数登录多房间,请确保传入相同的用户信息。
     */
    loginMultiRoom(roomID, config = { maxMemberCount:0, isUserStatusNotify: false, token:'' }){
        config = Object.assign({ maxMemberCount:0, isUserStatusNotify: false, token:'' }, config);
        this.ZegoNativeInstance.loginRoom({roomID, user, config});
    }

    /**
     * 退出房间。
     *
     * 详情描述:该接口会退出房间名为 roomID 的房间。
     * 业务场景:在同一个房间内用户可以进行直播、音视频通话等。
     * 调用时机:登录房间成功后,若不再使用房间功能,用户可以调用函数 [logoutRoom]。
     * 使用限制:无。
     * 注意事项:1. 退出房间会停止该用户的所有推拉流,引擎会停止,SDK 内部会主动停止本地预览。如果切换房间想保留预览能力,请使用 [switchRoom] 函数。2. 若用户登录房间,但传入 roomID 与已登录房间名不同,SDK 会返回失败。
     * 相关回调:调用此函数后会收到 [onRoomStateUpdate] 回调通知成功退出房间,同时同房间其他用户会接收到 [onRoomUserUpdate] 回调通知(开启 isUserStatusNotify 配置的前提下)。
     * 相关接口:用户可以调用 [loginRoom]、[switchRoom] 函数登录或更换房间。
     * @param {string} roomID - 房间 ID,最大长度为 128 字节的字符串。仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'.
     */
    logoutRoom(roomID){
        this.ZegoNativeInstance.logoutRoom({roomID});
    }

    /**
     * 使用配置进阶属性的方式切换房间。
     *
     * 详情描述:使用此函数可以让用户快速从一个房间切换到另外一个房间。
     * 业务场景:若需要快速切换到下一个房间,可调用此函数。
     * 调用时机:登录房间成功后。
     * 使用限制:无。
     * 注意事项:1. 当调用此函数后,当前正在推或拉的所有流都将会停止(但本地预览不会停止)。2. 为了防止 App 被恶意用户模拟登录,可以在切换房间之前加上鉴权验证,即 [config] 参数传入的 ZegoRoomConfig 对象中的 [token] 参数。此参数配置作用于即将切换过去的房间。3. 使用函数 [setRoomMode] 设置 ZegoRoomMode 为 ZEGO_ROOM_MODE_MULTI_ROOM 时,此函数不可用。
     * 隐私保护申明:请勿在此接口填写用户敏感信息,包括但不限于手机号、身份证号、护照编号、真实姓名等。
     * 相关回调:当用户调用 [switchRoom] 函数时,将会触发 [onRoomStateUpdate] 回调通知开发者当前用户连接房间的状态。
     * 相关接口:用户可以调用 [logoutRoom] 函数退出房间。
     * @param {string} fromRoomID - 当前处于的房间 ID。
     * @param {string} toRoomID - 需要登录的下一个房间 ID。
     * @param {ZegoRoomConfig} config - 房间进阶配置。
     */
    switchRoom(fromRoomID, toRoomID, config = { maxMemberCount:0, isUserStatusNotify: false, token:'' }){
        config = Object.assign({ maxMemberCount:0, isUserStatusNotify: false, token:'' }, config);
        this.ZegoNativeInstance.switchRoom({fromRoomID, toRoomID, config});
    }

    /**
     * 设置房间附加消息。
     *
     * 详情描述:用户调用此函数设置房间的附加消息。
     * 业务场景:可以设置一些房间相关的业务属性,比如是否有人在上麦。
     * 调用时机:登录房间成功后。
     * 使用限制:关于此函数的使用限制,请参考 https://doc-zh.zego.im/article/7581 或联系 ZEGO 技术支持。
     * 注意事项:key、value 非空,key.length < 128, value.length < 4096。新设置的 key 和 value 会覆盖旧的设置。
     * 相关回调:相同房间内的其他用户会通过 [onRoomExtraInfoUpdate] 回调函数获得通知。
     * 相关接口:无。
     * @param {string} roomID - 房间 ID。
     * @param {string} key - 附加消息键。
     * @param {string} value - 附加消息值。
     * @return {Promise<number>} - 设置房间附加信息执行结果通知
     */
    setRoomExtraInfo(roomID, key, value){
        return this.ZegoNativeInstance.setRoomExtraInfo({roomID, key, value});
    }

    /**
     * 开始推流,可选择推第二路流。
     *
     * 详情描述:用户将自己本地的音视频流推送到 ZEGO RTC 服务器 或 CDN,同一房间的其他用户通过 "streamID" 或 CDN 拉流地址就可以拉取该音视频流进行观看。
     * 业务场景:可以用于实时连麦、直播等场景下进行推流。
     * 调用时机:调用 [loginRoom] 加入房间后调用该函数。
     * 使用限制:无。
     * 注意事项:1. 开始推流前,用户可选择调用 [setVideoConfig] 设置相关视频参数,调用 [startPreview] 进行视频预览。2. 当推流成功之后,同房间内其他用户可通过监听 [onRoomStreamUpdate] 回调来获取流的新增情况。3. 在网络质量不佳的情况下,用户推流可能出现中断,SDK 会尝试重连并推流(连接成功后 SDK 会自动进行推流),开发者可通过监听 [onPublisherStateUpdate] 事件来获知当前推流状态以及错误信息。详情请参考 https://doc-zh.zego.im/article/10644.html。
     * @param {string} streamID - 流 ID,长度不超过256的字符串,需要在整个 AppID 内全局唯一,若出现在同一个 AppID 内,不同的用户各推了一条流且流名相同,将会导致后推流的用户推流失败。不可以包含 URL 关键字,否则推拉流失败。仅支持数字,英文字符 和 '~', '!', '@', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    startPublishingStream(streamID, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.startPublishingStream({streamID, channel});
    }

    /**
     * 停止推流,可停止指定通道的音视频流。
     *
     * 详情描述:用户停止发送本地的音视频流,房间内其他用户会收到流删除通知。
     * 业务场景:可以用于实时连麦、直播等场景下停止推流。
     * 调用时机:调用 [startPublishingStream] 开始推流后。
     * 使用限制:无。
     * 注意事项:1. 在停止推流之后,同房间内其他用户可通过监听 [onRoomStreamUpdate] 回调来收到流的删除通知。2. 如果用户已经启动推流,在推送新流(与之前的 streamID 不同)之前,必须要调用此函数停止当前流的推送,否则新流推送会返回失败。3. 在停止推流之后,开发者应该根据业务情况来决定是否需要停止本地预览。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    stopPublishingStream(channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.stopPublishingStream({channel});
    }

    /**
     * 设置指定推流通道的流附加信息。
     *
     * 详情描述:可通过此函数设置当前推流的流附加信息。流附加信息是流 ID 的附加信息标识,不同于流 ID 在推流过程中不可修改,流附加信息可以在对应流 ID 的推流中途修改。开发者可根据流附加信息来实现流 ID 相关的可变内容的同步。
     * 调用时机:在创建引擎 [initWithProfile/init] 之后,在推流 [startPublishingStream] 前后调用都可生效。
     * 使用限制:无。
     * 相关回调:结果会通过 [ZegoPublisherSetStreamExtraInfoCallback] 回调通知。
     * @param {string} extraInfo - 流附加信息,长度不超过1024的字符串。
     * @param {ZegoPublishChannel} channel - 推流通道。
     * @return {Promise<number>} - 设置流附加信息执行结果通知。
     */
    setStreamExtraInfo(extraInfo, channel = ZegoPublishChannel.Main){
        return this.ZegoNativeInstance.setStreamExtraInfo({extraInfo, channel});
    }

    /**
     * 启动/更新本地预览,支持设置其他通道的推流。
     *
     * 详情描述:用户通过调用此函数可以看到自己本地的画面。
     * 业务场景:可以用于实时连麦、直播等场景下的本地预览。
     * 调用时机:调用 [initWithProfile/init] 后。
     * 使用限制:无。
     * 注意事项:1. 预览功能不需要先登陆房间或推流,但是在退出房间之后 SDK 内部默认会主动停止预览。2. 可以通过再次调用此函数来切换视图或修改预览模式(ZegoViewMode)。用户只能在一个视图上预览,如果再次调用 [startPreview] 传入新的视图,则预览画面只会在新视图展现。3. 可以通过调用 [setVideoMirrorMode] 函数来设置预览画面的镜像模式,移动端默认开启预览画面的镜像效果。4. 调用此函数后,SDK 会启动音视频引擎,并尝试采集音频与视频。
     * @param {ZegoView} view - 启动预览时用于显示画面的视图。
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    startPreview(view, channel = ZegoPublishChannel.Main){
        view = Object.assign({ viewMode: ZegoViewMode.AspectFit, backgroundColor: 0x000000, preserveDrawingBuffer:false }, view);
        this.VideoViewManager.localGLRenders[channel] = new WebGLRender();
        this.VideoViewManager.localGLRenders[channel].setViewMode(view.viewMode);
        this.VideoViewManager.localGLRenders[channel].enablePreserveDrawingBuffer(view.preserveDrawingBuffer);
        this.VideoViewManager.localGLRenders[channel].initBkColor(view.backgroundColor);
        this.VideoViewManager.localGLRenders[channel].initGLfromCanvas(view.canvas);
        this.ZegoNativeInstance.startPreview({ channel });
    }

    /**
     * 停止本地预览,支持设置其他通道的推流
     *
     * 当本地不需要预览画面时可调用此函数停止预览,此时预览的画面停留在最后一帧。
     * 停止预览不会影响推流、拉流功能。
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    stopPreview(channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.stopPreview({ channel });
        if(this.VideoViewManager.localGLRenders[channel])
        {
            this.VideoViewManager.localGLRenders[channel].uninit2d();
            this.VideoViewManager.localGLRenders[channel] = null;
        }
    }

    /**
     * 设置视频配置,支持设置其他通道的推流。
     *
     * 详情描述:设置视频帧率、码率、视频采集分辨率、视频编码输出分辨率等视频配置。
     * 业务场景:不同业务场景下的建议配置:https://doc-zh.zego.im/article/10365。
     * 默认值:默认视频采集分辨率为 360p,视频编码输出分辨率为 360p,码率为 600 kbps,帧率为 15 fps。
     * 调用时机:调用 [initWithProfile/init] 之后。
     * 使用限制:需要在推流前设置好相关视频配置,在推流后仅支持编码分辨率和码率的修改。
     * 注意事项:移动端分辨率的宽高与 PC 端分辨率的宽高是相反的,例:移动端的 360p 的分辨率为 360x640,而 PC 端 360p 的分辨率为 640x360。
     * @param {(ZegoVideoConfigPreset|ZegoVideoConfig)} config - 视频配置,SDK 提供常用的分辨率、帧率和码率的组合值,也可自定义分辨率、帧率和码率。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    setVideoConfig(config, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.setVideoConfig({config, channel});
    }

    /**
     * 获取当前视频配置,支持设置其他通道的推流
     *
     * 可通过此函数获取指定推流通道当前的视频帧率、码率,视频采集分辨率,视频编码输出分辨率。
     * @param {ZegoPublishChannel} channel - 推流通道
     * @return {ZegoVideoConfig} - 视频配置对象
     */
    getVideoConfig(channel = ZegoPublishChannel.Main){
        return this.ZegoNativeInstance.getVideoConfig({channel});
    }

    /**
     * 设置镜像模式,支持设置其他通道的推流。
     *
     * 详情描述:设置本地预览视频以及推送的视频是否开启镜像模式,具体镜像模式可以参考:https://doc-zh.zego.im/article/10365。
     * 调用时机:调用 [initWithProfile/init] 之后。
     * 使用限制:无。
     * @param {ZegoVideoMirrorMode} mirrorMode - 预览或推流的镜像模式。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    setVideoMirrorMode(mirrorMode, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.setVideoMirrorMode({mirrorMode, channel});
    }

    /**
     * 设置音频质量配置。
     *
     * 详情描述:可通过此函数设置音频编码类型、码率、音频声道的组合值。若预设的值无法满足开发者的场景,开发者可自行根据业务要求设置符合的参数。
     * 默认值:默认的音频配置参考 [ZegoAudioConfig] 的默认值。
     * 调用时机:在创建引擎 [initWithProfile/init] 后,且在推流 [startPublishingStream] 前设置。
     * 使用限制:无。
     * 注意事项:作用于主推流通道 ZegoPublishChannel.Main。
     * 相关接口:[getAudioConfig]。
     * @param {(ZegoAudioConfigPreset|ZegoAudioConfig)} config - 音频质量配置。
     */
    setAudioConfig(config){
        this.ZegoNativeInstance.setAudioConfig({config});
    }

    /**
     * 获取当前音频质量配置。
     *
     * 详情描述:可通过此函数获取当前的音频编码类型、码率、音频声道的组合值。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 使用限制:无。
     * 注意事项:作用于主推流通道 ZegoPublishChannel.Main。
     * 相关接口:[setAudioConfig]。
     * @return {ZegoAudioConfig} - 音频质量配置。
     */
    getAudioConfig(){
        return this.ZegoNativeInstance.getAudioConfig({});
    }
    
    /**
     * 获取推流的快照,支持设置其他通道的推流。
     *
     * 请在调用接口 [startPublishingStream] 或 [startPreview] 之后调用。
     * 快照的分辨率是 [setVideoConfig] 中设置的编码分辨率。如果您需要将其更改为采集分辨率,请调用 [setCapturePipelineScaleMode] 将采集通道的缩放模式更改为[Post]。
     * @param {ZegoPublishChannel} channel - 推流通道
     * @return {Promise<number, string>} - 快照错误代码和 jpg 格式图像的 base64 字符串。
     */
    takePublishStreamSnapshot(channel = ZegoPublishChannel.Main){
        return this.ZegoNativeInstance.takePublishStreamSnapshot({channel});
    }

    /**
     * 停止或恢复发送指定推流通道的音频流。
     *
     * 详情描述:推流时可调用此函数实现不推音频数据流,本地仍会采集和处理音频,但不向网络发送音频数据。
     * 调用时机:在创建引擎 [initWithProfile/init] 后调用生效。
     * 使用限制:无。
     * 相关回调:如果在本地设置了停止发送音频流,拉本地流的远端用户可以通过监听 [onRemoteMicStateUpdate] 回调收到 `Mute` 的状态变更通知。
     * 相关接口:[mutePublishStreamVideo]。
     * @param {boolean} mute - 是否停止发送音频流;true 表示不发送音频流;false 表示发送音频流;默认为 false。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    mutePublishStreamAudio(mute, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.mutePublishStreamAudio({mute, channel});
    }

    /**
     * 停止或恢复发送指定推流通道的视频流。
     *
     * 详情描述:推流时可调用此函数实现不推视频流,本地摄像头仍能正常工作,能正常采集,预览和处理视频画面,但不向网络发送视频数据。
     * 调用时机:在创建引擎 [initWithProfile/init] 后调用生效。
     * 使用限制:无。
     * 相关回调:如果在本地设置了停止发送视频流,拉本地流的远端用户可以通过监听 [onRemoteCameraStateUpdate] 回调收到 `Mute` 的状态变更通知。
     * 相关接口:[mutePublishStreamAudio]。
     * @param {boolean} mute - 是否停止发送视频流;true 表示只发送音频流不发送视频流;false 表示同时发送音频和视频流;默认为 false。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    mutePublishStreamVideo(mute, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.mutePublishStreamVideo({mute, channel});
    }

    /**
     * 开始或停止流量控制。
     *
     * 详情描述:开启流量控制可以使 SDK 根据当前上行网络环境状况,或者在1 对1 互动场景下根据对方下行网络环境状况,调节音视频推流码率大小,以保障效果流畅。同时,可进一步指定流量控制的属性来调整相应的控制策略。
     * 默认值:默认开启。
     * 调用时机:在创建引擎 [initWithProfile/init] 后,在推流 [startPublishingStream] 之前调用生效。
     * 使用限制:仅支持 RTC 推流。
     * 注意事项:作用于主推流通道 ZegoPublishChannel.Main。
     * @param {boolean} enable - 是否使用流量控制。true 表示开启流控,false 表示关闭流控。默认为 true。
     * @param {number} property - 流量控制的属性,位掩码格式。具体可设置为 [ZegoTrafficControlProperty] 的属性的一个或多个枚举组合。默认为 AdaptiveFPS。
     */
    enableTrafficControl(enable, property){
        this.ZegoNativeInstance.enableTrafficControl({enable, property});
    }

    /**
     * 设置流量控制的最低视频码率阈值。
     *
     * 详情描述:设置流量控制时视频码率达到最低阈值时的控制策略。当码率低于最低阈值时,可以选择不发送视频数据或者以极低帧率发送。
     * 默认值:无视频码率最低阈值的控制效果。
     * 调用时机:在创建引擎 [initWithProfile/init] 后,在推流 [startPublishingStream] 前调用生效。
     * 使用限制:必须开启流量控制 [enableTrafficControl]。
     * 注意事项:作用于主推流通道 ZegoPublishChannel.Main。
     * 相关接口:[enableTrafficControl]。
     * @param {number} bitrate - 流量控制的最低视频码率阈值,单位为 kbps。
     * @param {ZegoTrafficControlMinVideoBitrateMode} mode - 低于最低码率时的视频发送模式。
     */
    setMinVideoBitrateForTrafficControl(bitrate, mode){
        this.ZegoNativeInstance.setMinVideoBitrateForTrafficControl({bitrate, mode});
    }
    
    /**
     * 设置推流端采集音量。
     *
     * 详情描述:此函数用于在设备采集音量的基础上做增益处理,本端用户可控制往远端发送音频流的声音大小。
     * 默认值:默认为 100。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 使用限制:在推流途中可以动态设置采集音量。
     * 相关接口:设置拉流音量 [setPlayVolume]。
     * @param {number} volume - 音量增益百分比,范围为 0 ~ 200,默认值为 100,表示为设备原始采集音量的 100%.
     */
    setCaptureVolume(volume){
        this.ZegoNativeInstance.setCaptureVolume({volume});
    }

    /**
     * 设置音频采集双声道模式。
     *
     * 详情描述:此函数用于设置音频的采集声道模式,当开发者开启双声道采集后,使用专门的双声道采集设备,可以采集到双声道的音频数据并进行推流。
     * 业务场景:在一些比较专业的场景里,用户对声音的效果尤为敏感,比如语音电台、乐器演奏,此时就需要对双声道和高音质的支持。
     * 默认值:默认 None,即单声道采集。
     * 调用时机:需要在 [initWithProfile/init] 之后,在 [startPublishingStream]、 [startPlayingStream]、 [startPreview]、 [createMediaPlayer] 和 [createAudioEffectPlayer] 之前调用才有效。
     * 使用限制:无。
     * 相关接口:当推流时需要同时通过 [setAudioConfig] 函数开启双声道音频编码功能。
     * @param {ZegoAudioCaptureStereoMode} mode - 双声道采集模式。
     */
    setAudioCaptureStereoMode(mode){
        this.ZegoNativeInstance.setAudioCaptureStereoMode({mode});
    }

    /**
     * 增加转推至 CDN 的 URL。
     *。
     * 详情描述:将 ZEGO RTC 服务器的音视频流转推至自定义的 CDN 内容分发网络,延迟高但是支持高并发拉流。
     * 业务场景:1. 常用于对延迟没有特别高要求的大规模直播场景。2. 由于 ZEGO RTC 服务器本身可配置支持 CDN 内容分发网络,此函数主要为自身拥有 CDN 内容分发服务的开发者使用。3. 此函数支持动态转推至多个 CDN 内容分发网络,因此开发者可以使用此函数来作为 CDN 内容分发服务的一个容灾方案。
     * 调用时机:在调用 [initWithProfile/init] 函数创建引擎后。
     * 使用限制:当调用 [enablePublishDirectToCDN] 函数设置为 true 将流直推到 CDN 时,再调用本函数将无效。
     * 相关接口:删除转推至 CDN 的 URL [removePublishCdnUrl],结果回调函数 [onPublisherRelayCDNStateUpdate]。
     * @param {string} streamID - 流 ID。
     * @param {string} targetURL - CDN 转推地址,支持的转推地址格式有 rtmp.
     * @return {Promise<number>} - 更新 CDN 转推结果通知。
     */
    addPublishCdnUrl(streamID, targetURL){
        return this.ZegoNativeInstance.addPublishCdnUrl({streamID, targetURL});
    }

    /**
     * 删除转推至 CDN 的 URL。
     *
     * 详情描述:当已经通过 [addPublishCdnUrl] 添加了某个 CDN 转推地址,需要将流停止转推时调用此函数。
     * 调用时机:在调用 [initWithProfile/init] 函数创建引擎后。
     * 使用限制:当调用 [enablePublishDirectToCDN] 函数设置为 true 将流直推到 CDN 时,再调用本函数将无效。
     * 注意事项:此函数并不会停止推往 ZEGO RTC 服务器的音视频流。
     * 相关接口:增加转推至 CDN 的 URL [addPublishCdnUrl],结果回调函数 [onPublisherRelayCDNStateUpdate]。
     * @param {string} streamID - 流 ID。
     * @param {string} targetURL - CDN 转推地址,支持的转推地址格式有 rtmp.
     * @return {Promise<number>} - 更新 CDN 转推结果通知。
     */
    removePublishCdnUrl(streamID, targetURL){
        return this.ZegoNativeInstance.removePublishCdnUrl({streamID, targetURL});
    }

    /**
     * 是否直接推流到 CDN(不经过 ZEGO RTC 服务器), 支持设置其他通道的推流。
     *
     * 详情描述:是否不经过 ZEGO RTC 服务器直接推流到 CDN。
     * 业务场景:常用于对延迟没有特别高要求的大规模直播场景。
     * 默认值:默认为 false,不开启直推。
     * 调用时机:在创建引擎 [initWithProfile/init]后,开始推流[startPublishingStream] 前。
     * 注意事项:直推 CDN 功能在网络传输过程中不经过 ZEGO 实时音视频云,无法使用 ZEGO 的超低延迟音视频服务。
     * 相关接口:动态转推至 CDN 函数 [addPublishCdnUrl]、[removePublishCdnUrl]。
     * @param {boolean} enable - 是否开启直推 CDN;true 表示开启直推 CDN;false 表示不开启直推 CDN;默认为 false。
     * @param {ZegoCDNConfig} config - CDN 配置,若为 null 则使用 Zego 的后台配置。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    enablePublishDirectToCDN(enable, config, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.enablePublishDirectToCDN({enable, config, channel});
    }

    /**
     * 设置推流水印,支持设置其他通道的推流。
     *
     * 详情描述:给推流画面设置水印。
     * 业务场景:常用于标识推流来源的场景。
     * 调用时机:在调用 [initWithProfile/init] 函数创建引擎后。
     * 注意事项:水印的布局不能超出推流的视频编码分辨率。可在推流前或推流中途任意时刻设置。
     * @param {ZegoWatermark} watermark - 水印布局左上角为坐标系原点,区域不能超过编码分辨率设置的大小。若为空表示取消水印。
     * @param {boolean} isPreviewVisible - 是否本地预览能看见水印。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    setPublishWatermark(watermark, isPreviewVisible, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.setPublishWatermark({watermark, isPreviewVisible, channel});
    }

    /**
     * 设置媒体增强补充信息类型。
     *
     * 详情描述:SDK 默认使用 ZEGO 自行定义的 SEI 类型包装数据,且此类型是 SEI 标准未规定的类型。当开发者需要使用第三方解码器解码,会导致解不出正确的 SEI,需要调用 [setSEIConfig] 函数更换 SDK 发送 SEI 的类型为 UserUnregister 类型。
     * 业务场景:当开发者使用第三方解码器解码 SEI 时需要执行该函数。
     * 调用时机:在创建引擎 [initWithProfile/init]后,开始推流[startPublishingStream] 前。
     * 使用限制:无。
     * @param {ZegoSEIConfig} config - SEI 类型配置。默认使用 ZEGO 定义的 SEI。
     */
    setSEIConfig(config){
        this.ZegoNativeInstance.setSEIConfig({config});
    }

    /**
     * 发送媒体增强补充信息。
     *
     * 详情描述:在推流传输音视频流数据同时,发送流媒体增强补充信息来同步一些其他附加信息。
     * 业务场景:一般用于如同步音乐歌词或视频画面精准布局等场景,可选择使用发送 SEI。
     * 调用时机:在开始推流[startPublishingStream] 后。
     * 使用限制:1 秒钟不要超过30次,SEI 数据长度限制为 4096 字节。
     * 注意事项:由于 SEI 信息跟随视频帧,由于网络问题有可能丢帧,因此 SEI 信息也有可能丢,为解决这种情况,应该在限制频率内多发几次。
     * 相关接口:当推流方发送 SEI 后,拉流方可通过监听 [onPlayerRecvSEI] 的回调获取 SEI 内容。
     * @param {Uint8Array} data - SEI 内容。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    sendSEI(data, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.sendSEI({data, channel});
    }

    /**
     * 开/关硬件编码。
     *
     * 详情描述:推流时是否采用硬件编码的开关,开启硬解编码后会使用 GPU 进行编码,降低 CPU 使用率。
     * 调用时机:在推流前设置才能生效,如果在推流后设置,停推后重新推流可以生效。
     * 注意事项:由于少部分机型设备硬编支持不是特别好,SDK 默认使用软件编码的方式。若开发者在某些机型测试时发现推大分辨率音视频流时设备发热严重,可考虑调用此函数开启硬编的方式。
     * @param {boolean} enable - 是否开启硬件编码;true 表示开启硬编;false 表示关闭硬编;默认为 false。
     */
    enableHardwareEncoder(enable){
        this.ZegoNativeInstance.enableHardwareEncoder({enable});
    }

    /**
     * 设置采集缩放时机,视频数据是采集的时候立即缩放还是编码时才进行缩放。
     *
     * 调用时机:此函数需要在调用 [initWithProfile/init] 之后,调用预览 [startPreview] 或推流 [startPublishingStream] 前设置有效。
     * 注意事项:主要影响是当采集分辨率与编码分辨率不同的时候,是否影响本地预览情况。
     * @param {ZegoCapturePipelineScaleMode} mode - 采集缩放时机。
     */
    setCapturePipelineScaleMode(mode){
        this.ZegoNativeInstance.setCapturePipelineScaleMode({mode});
    }

    /**
     * 开始拉流(从 ZEGO RTC 服务器或第三方 CDN)。
     *
     * 详情描述:从 ZEGO RTC 服务器或第三方 CDN 拉取远端用户的音视频流进行互通。
     * 业务场景:在实时连麦或直播场景下,开发者可通过监听 [onRoomStreamUpdate] 事件回调来获取所在房间内新增的流信息,并调用此接口传入 "streamID" 进行拉流操作。
     * 调用时机:调用 [loginRoom] 加入房间后调用该函数。
     * 使用限制:无。
     * 注意事项:1. 开发者可通过再次调用此函数实现切换拉流 canvas 的操作(streamID 必须一样)。同一条流只能在唯一的视图中拉取展示,如果调用 [startPlayingStream] 传入相同的 "streamID" 和不同的视图,画面只会在新视图展现。2. 首次拉流时如果因网络原因拉流失败或拉流中断,SDK 会在 20min 内多次尝试重连并拉流。3. 在网络质量不佳的情况下,用户拉流可能出现中断,SDK 会尝试重连并拉流,可通过监听 [onPlayerStateUpdate] 事件来获知当前拉流状态以及错误信息。详情请参考 https://doc-zh.zego.im/faq/reconnect。4. 如果拉取不存在的 "streamID",SDK 会持续尝试拉取,在该 streamID 对应的音视频流被成功推送后,该流可以真正被拉取到。
     * @param {string} streamID - 流 ID,长度不超过 256 字节的字符串。仅支持数字,英文字符 和 '~', '!', '@', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'。
     * @param {ZegoView} view - 启动预览时用于显示画面的视图。
     * @param {ZegoPlayerConfig} config - 拉流进阶配置。
     */
    startPlayingStream(streamID, view, config = { cdnConfig: null, videoLayer: ZegoPlayerVideoLayer.Auto}){
        view = Object.assign({ viewMode: ZegoViewMode.AspectFit, backgroundColor: 0x000000, preserveDrawingBuffer:false }, view);
        config = Object.assign({ cdnConfig: null, videoLayer: ZegoPlayerVideoLayer.Auto }, config);
        this.VideoViewManager.remoteGLRenders[streamID] = new WebGLRender();
        this.VideoViewManager.remoteGLRenders[streamID].setViewMode(view.viewMode);
        this.VideoViewManager.remoteGLRenders[streamID].enablePreserveDrawingBuffer(view.preserveDrawingBuffer);
        this.VideoViewManager.remoteGLRenders[streamID].initBkColor(view.backgroundColor);
        this.VideoViewManager.remoteGLRenders[streamID].initGLfromCanvas(view.canvas);
        this.ZegoNativeInstance.startPlayingStream({ streamID, config });
    }

    /**
     * 停止拉流。
     *
     * 详情描述:停止从 ZEGO RTC 服务器拉取远端用户的音视频流。
     * 业务场景:在实时连麦场景下,开发者可通过监听 [onRoomStreamUpdate] 事件回调来获取所在房间内删除的流信息,并调用此接口传入 "streamID" 进行停止拉流操作。
     * 调用时机:调用 [loginRoom] 加入房间后调用该函数。
     * 使用限制:无。
     * 注意事项:停止拉流后对此条流此前设置的属性如 [setPlayVolume]、[mutePlayStreamAudio]、[mutePlayStreamVideo] 等拉流相关的配置都会失效,需要在下次拉流之前重新设置。
     * @param {string} streamID - 流 ID。
     */
    stopPlayingStream(streamID){
        this.ZegoNativeInstance.stopPlayingStream({ streamID });
        if(this.VideoViewManager.remoteGLRenders[streamID])
        {
            this.VideoViewManager.remoteGLRenders[streamID].uninit2d();
            this.VideoViewManager.remoteGLRenders[streamID] = null;
        }
    }
    
    /**
     * 获取播放流的快照.
     *
     * 请在调用拉流接口 [startPlayingStream] 后调用。
     * @param {string} streamID - 流ID
     * @return {Promise<number, string>} - 快照错误代码(错误代码)和jpg格式图像的base64字符串(图像)。
     */
    takePlayStreamSnapshot(streamID){
        return this.ZegoNativeInstance.takePlayStreamSnapshot({streamID});
    }
    
    
    
    

    /**
     * 设置拉流音量。
     *
     * 详情描述:设置拉流的声音大小,本端用户可控制音频流的播放音量。
     * 调用时机:[startPlayingStream] 后调用。
     * 使用限制:无。
     * 注意事项:停止拉流后,再次拉流需要重新设置。
     * @param {string} streamID - 流 ID。
     * @param {number} volume - 音量百分比,取值范围为 0 ~ 200,默认值为 100。
     */
    setPlayVolume(streamID, volume){
        this.ZegoNativeInstance.setPlayVolume({streamID, volume});
    }

    /**
     * 【已废弃】设置选取拉流视频图层。
     *
     * 此函数在 0.24.3 版本以后已废弃, 请使用 [setPlayStreamVideoType] 代替。
     * 当推流方通过 [setVideoConfig] 设置了 codecID 为 SVC 时,拉流方可以动态设置选用标准图层还是基础图层(基础图层分辨率为标准图层的二分之一)。
     * 一般情况下,在网络较弱或者渲染的 UI 窗体较小的情况下,可以选择使用拉取基础图层的视频来达到节省带宽的目的。
     * 在拉流前后均可设置。
     * @param {string} streamID - 流 ID
     * @param {ZegoPlayerVideoLayer} videoLayer - 拉流图层,默认为 AUTO
     * @deprecated 此函数在 0.24.3 版本以后已废弃, 请使用 [setPlayStreamVideoType] 代替。
     */
    setPlayStreamVideoLayer(streamID, videoLayer){
        this.ZegoNativeInstance.setPlayStreamVideoLayer({streamID, videoLayer});
    }

    /**
     * 拉流是否可接收指定音频数据。
     *
     * 详情描述:在实时音视频互动过程中,本地用户可根据需要,通过此函数控制拉流时是否接收指定远端用户的音频数据,当开发者不接收音频收据时,可降低硬件和网络的开销。
     * 业务场景:当开发者需要快速关闭、恢复远端音频时,可调用此函数。相比重新拉流,能极大降低耗时,提升互动体验。
     * 调用时机:在调用 [initWithProfile/init] 后可调用此函数。
     * @param {string} streamID - 流 ID。
     * @param {boolean} mute - 拉流时是否可以接收指定远端用户的音频数据,“true” 表示禁止,“false” 表示接收,默认值为 “false”。
     */
    mutePlayStreamAudio(streamID, mute){
        this.ZegoNativeInstance.mutePlayStreamAudio({streamID, mute});
    }

    /**
     * 拉流是否可接收指定视频数据。
     *
     * 详情描述:在实时音视频互动过程中,本地用户可根据需要,通过此函数控制拉流时是否接收指定远端用户的视频数据,当开发者不接收音频收据时,可降低硬件和网络的开销。
     * 业务场景:当开发者需要快速关闭、恢复观看远端视频画面时,可调用此函数。相比重新拉流,能极大降低耗时,提升互动体验。
     * 调用时机:在调用 [initWithProfile/init] 后可调用此函数。
     * 注意事项:只有当 [muteAllPlayStreamVideo] 函数设置为 “false”时,此函数才有效。
     * 相关接口:可调用 [muteAllPlayStreamVideo] 函数控制是否接收所有视频数据。必须当 [muteAllPlayStreamVideo] 和 [mutePlayStreamVideo] 两个函数同时设置为 "false" 时,本地用户拉流时才能接收远端用户的视频数据:1. 当调用 [muteAllPlayStreamVideo(true)] 函数时,全局生效,即本地用户会禁止接收所有远端用户的视频数据,此时无论在 [muteAllPlayStreamVideo] 之前还是之后调用 [mutePlayStreamVideo] 函数都不生效。2. 当调用 [muteAllPlayStreamVideo(false)] 函数时,本地用户可以接收所有远端用户的视频数据,此时可再通过 [mutePlayStreamVideo] 函数控制是否接收单条视频数据。调用 [mutePlayStreamVideo(true, streamID)] 函数则本地用户可以接收该 "streamID" 之外的其他视频数据;调用 [mutePlayStreamVideo(false, streamID)] 函数则本地用户可以接收 "streamID" 的视频数据。
     * @param {string} streamID - 流 ID。
     * @param {boolean} mute - 拉流时是否可以接收指定远端用户的视频数据,“true” 表示禁止,“false” 表示接收,默认值为 “false”。
     */
    mutePlayStreamVideo(streamID, mute){
        this.ZegoNativeInstance.mutePlayStreamVideo({streamID, mute});
    }

    /**
     * 拉流是否可接收所有视频数据
     *
     * 详情描述:在实时音视频互动过程中,本地用户可根据需要,通过此函数控制拉流时是否接收所有远端用户的视频数据(包括在调用该函数后新加入房间的用户所推的视频流)。默认情况下,用户加入房间后可以接收所有远端用户推送的视频数据。当开发者不接收音频收据时,可降低硬件和网络的开销。
     * 业务场景:当开发者需要快速关闭、恢复观看远端视频画面时,可调用此函数。相比重新拉流,能极大降低耗时,提升互动体验。
     * 调用时机:在调用 [initWithProfile/init] 后可调用此函数。
     * 相关接口:可调用 [mutePlayStreamVideo] 函数控制是否接收单条视频数据。必须当 [muteAllPlayStreamVideo] 和 [mutePlayStreamVideo] 两个函数同时设置为 "false" 时,本地用户拉流时才能接收远端用户的视频数据: 1. 当调用 [muteAllPlayStreamVideo(true)] 函数时,全局生效,即本地用户会禁止接收所有远端用户的视频数据,此时无论在 [muteAllPlayStreamVideo] 之前还是之后调用 [mutePlayStreamVideo] 函数都不生效。 2. 当调用 [muteAllPlayStreamVideo(false)] 函数时,本地用户可以接收所有远端用户的视频数据,此时可再通过 [mutePlayStreamVideo] 函数控制是否接收单条视频数据。调用 [mutePlayStreamVideo(true, streamID)] 函数则本地用户可以接收该 "streamID" 之外的其他视频数据;调用 [mutePlayStreamVideo(false, streamID)] 函数则本地用户可以接收 "streamID" 的视频数据。
     * @param {boolean} mute - 拉流时是否可以接收所有远端用户的视频数据,“true” 表示禁止,“false” 表示接收,默认值为 “false”。
     */
    muteAllPlayStreamVideo(mute){
        this.ZegoNativeInstance.muteAllPlayStreamVideo({mute});
    }

    /**
     * 开/关硬件解码。
     *
     * 详情描述:拉流时是否使用硬件解码,开启硬件解码后 SDK 会使用 GPU 进行解码,降低 CPU 使用率。
     * 业务场景:若开发者在某些机型测试时发现拉大分辨率音视频流时设备发热严重,可考虑调用此函数开启硬件解码的方式。
     * 默认值:未调用此接口时,默认关闭硬解。
     * 调用时机:此函数需要在 [initWithProfile/init] 创建实例后调用。
     * 使用限制:无。
     * 注意事项:在拉流前设置才能生效,如果在拉流后设置,停止拉流后重新拉流才生效,此配置生效后,在下次调用生效前一直有效。
     * @param {boolean} enable - 是否开启硬解开关,true 表示开启硬解,false 表示关闭硬解。
     */
    enableHardwareDecoder(enable){
        this.ZegoNativeInstance.enableHardwareDecoder({enable});
    }

    /**
     * 开/关帧顺序检测。
     *
     * 详情描述:设置是否开启帧顺序检查,开启则不支持B帧,关闭则支持B帧。
     * 业务场景:拉cdn的流时,开启帧顺序检测可防止花屏。
     * 默认值:未调用此接口时,默认开启帧顺序检测。
     * 调用时机:此函数需要在 [initWithProfile/init] 创建实例后调用。
     * 使用限制:无。
     * 注意事项:拉流过程中关闭顺序检测可能出现短暂花屏。
     * @param {boolean} enable - 是否开启帧顺序检测,true 表示开启帧顺序检测,不支持 B 帧,false 表示关闭帧顺序检测,支持 B 帧。
     */
    enableCheckPoc(enable){
        this.ZegoNativeInstance.enableCheckPoc({enable});
    }

    /**
     * 开始混流任务。
     *
     * 详情描述:向 ZEGO RTC 服务器发起混流请求,服务器会寻找当前正在推的流,并根据 SDK 请求的混流任务的参数进行图层混合。当需要更新混流任务时,即输入流增加或减少时需要更新输入流列表,此时可以更新 [ZegoMixerTask] 对象 inputList 的字段并再次调用本函数传入相同的 [ZegoMixerTask] 对象更新混流任务。
     * 业务场景:常用于需要多个视频画面合成一个视频时使用混流,比如教育类,直播老师和学生的画面。
     * 调用时机:调用 [loginRoom] 登录房间后。
     * 使用限制:无。
     * 注意事项:由于客户端设备的性能考虑,SDK 的混流是在 ZEGO RTC 服务器开启混流任务进行混流。若请求开启混流任务发生异常,例如最常见的混流的输入流不存在,将会从 callback 回调的错误码给出。具体错误码请参考 常见错误码文档 https://doc-zh.zego.im/zh/4378.html。若中途某条输入流不存在了,混流任务会自动重试拉这条输入流 90 秒,90 秒之后不再重试。若所有输入流均不存在了,90秒之后服务器会自动停止混流任务。
     * 相关回调:可通过 [onMixerRelayCDNStateUpdate] 获取混流转推 CDN 状态更新通知,可通过 [onMixerSoundLevelUpdate] 获取混流中的每条单流的的声浪更新通知。
     * 相关接口:可通过 [stopMixerTask] 函数停止混流。
     * @param {ZegoMixerTask} task - 混流任务对象。是否必填:是。
     * @return {Promise<number, string>} - 开始混流任务结果
     */
    startMixerTask(task){
        return this.ZegoNativeInstance.startMixerTask({task});
    }

    /**
     * 停止混流任务。
     *
     * 详情描述:向 ZEGO RTC 服务器发起结束混流请求。
     * 业务场景:常用于需要多个视频画面合成一个视频时使用混流,比如教育类,直播老师和学生的画面。
     * 调用时机:调用 [startMixerTask] 开始混流后。
     * 使用限制:无。
     * 注意事项:若开发者在未停止上一个混流任务的情况下启动下一个混流任务,上一个混流任务不会自动停止,直到上一个混流任务的输入流持续 90 秒都不存在之后。在启动下一个混流任务前,应当先停止上一个混流任务,以免当一个主播已经开启下一个混流任务与其他主播混流时,观众依然在拉上一个混流任务的输出流。
     * 相关接口:可通过 [startMixerTask] 函数开始混流。
     * @param {ZegoMixerTask} task - 混流任务对象。是否必填:是。
     * @return {Promise<number>} - 停止混流任务结果
     */
    stopMixerTask(task){
        return this.ZegoNativeInstance.stopMixerTask({task});
    }

    /**
    /**
     * 设置是否静音(关闭麦克风)。
     *
     * 详情描述:此函数用于控制是否使用采集到的音频数据,静音(关闭麦克风)将会使用静音数据替换设备采集到的音频数据进行推流,此时仍然会占用麦克风设备。
     * 默认值:默认为 "false",即不静音。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 使用限制:无。
     * 相关接口:若想要真正让 SDK 放弃占用麦克风,例如实现 App 退到后台后释放麦克风占用等功能,可调用 [enableAudioCaptureDevice] 函数开关音频采集设备。可使用 [isMicrophoneMuted] 来检查麦克风是否静音。
     * @param {boolean} mute - 是否静音(关闭麦克风);"true" 表示静音(关闭麦克风);"false" 表示开启麦克风。
     */
    muteMicrophone(mute){
        this.ZegoNativeInstance.muteMicrophone({mute});
    }

    /**
     * 检查麦克风是否设置为静音。
     *
     * 详情描述:用于判断麦克风是否被设置为静音。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 使用限制:无。
     * 相关接口:[muteMicrophone]。
     * @return {boolean} - 麦克风是否静音;"true" 表示麦克风静音;"false" 表示麦克风开启中(没有被静音)。
     */
    isMicrophoneMuted(){
        return this.ZegoNativeInstance.isMicrophoneMuted({});
    }

    /**
     * 设置是否静音(关闭音频输出)。
     *
     * 详情描述:设置静音后,SDK 所有声音都不会播放,包括拉流、媒体播放器等。但 SDK 仍会占用音频输出设备。
     * 默认值:默认为 "false",即不静音。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 使用限制:无。
     * @param {boolean} mute - 是否静音(关闭音频输出);"true" 表示静音(关闭音频输出);"false" 表示开启音频输出。
     */
    muteSpeaker(mute){
        this.ZegoNativeInstance.muteSpeaker({mute});
    }

    /**
     * 检查音频输出是否静音。
     *
     * 详情描述:用于判断音频输出是否静音。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 使用限制:无。
     * 相关接口:[muteSpeaker]。
     * @return {boolean} - 音频输出是否静音;"true" 表示音频输出静音;"false" 表示音频输出开启中(没有被静音)。
     */
    isSpeakerMuted(){
        return this.ZegoNativeInstance.isSpeakerMuted({});
    }

    /**
     * 获取音频设备列表
     *
     * @param {ZegoAudioDeviceType} deviceType - 音频设备类型
     * @return {ZegoDeviceInfo[]} - 音频设备列表
     */
    getAudioDeviceList(deviceType){
        return this.ZegoNativeInstance.getAudioDeviceList({deviceType});
    }

    /**
     * 获取默认音频设备 ID
     *
     * @param {ZegoAudioDeviceType} deviceType - 音频设备类型
     * @return {string} - 默认音频设备 ID
     */
    getDefaultAudioDeviceID(deviceType){
        return this.ZegoNativeInstance.getDefaultAudioDeviceID({deviceType});
    }

    /**
     * 选择使用某个音频设备
     *
     * @param {string} deviceID - 通过 [getAudioDeviceList] 获取的某个设备的 ID
     * @param {ZegoAudioDeviceType} deviceType - 音频设备类型
     */
    useAudioDevice(deviceID, deviceType){
        this.ZegoNativeInstance.useAudioDevice({deviceID, deviceType});
    }

    /**
     * 获取音频设备音量
     *
     * @param {ZegoAudioDeviceType} deviceType - 音频设备类型
     * @param {string} deviceID - 通过 [getAudioDeviceList] 获取的某个设备的 ID
     * @return {number} - 设备音量
     */
    getAudioDeviceVolume(deviceType, deviceID){
        return this.ZegoNativeInstance.getAudioDeviceVolume({deviceType, deviceID});
    }

    /**
     * 设置音频设备音量。
     *
     * 可能因为系统限制导致直接操作系统设备失败,请优先使用 [setCaptureVolume] 和 [setPlayVolume] 来调节推拉流音量。
     * @param {ZegoAudioDeviceType} deviceType - 音频设备类型
     * @param {string} deviceID - 通过 [getAudioDeviceList] 获取的某个设备的 ID
     * @param {number} volume - 设备音量
     */
    setAudioDeviceVolume(deviceType, deviceID, volume){
        this.ZegoNativeInstance.setAudioDeviceVolume({deviceType, deviceID, volume});
    }

    /**
     * 开/关音频采集设备。
     *
     * 详情描述:此函数用于控制是否释放音频采集设备。关闭音频采集设备,则 SDK 不会再占用音频设备,当然如果此时正在推流,也不会产生音频数据。
     * 使用场景:当用户从不需要用到音频的时候,可以调用此函数关闭音频采集。
     * 默认值:默认为 "false"。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 使用限制:无。
     * 相关接口:硬件上关闭或打开麦克风是耗时操作,用户频繁操作时有一定的性能开销,一般推荐使用 [muteMicrophone]。
     * @param {boolean} enable - 是否开启音频采集设备;"true" 表示打开音频采集设备;"false" 表示关闭音频采集设备。
     */
    enableAudioCaptureDevice(enable){
        this.ZegoNativeInstance.enableAudioCaptureDevice({enable});
    }

    /**
     * 开/关摄像头,支持设置其他通道的推流。
     *
     * 详情描述:此函数用于控制是否启动摄像头的采集,关闭摄像头后,将不会进行视频采集,此时推流也将没有视频数据。
     * 默认值:默认为 "true",即打开摄像头。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 使用限制:无。
     * 注意事项:在使用自定义视频采集功能 [enableCustomVideoCapture] 的情况下,由于开发者接管了视频数据的采集,SDK 不再负责视频数据的采集,但此函数依然会影响是否进行编码的行为。因此开发者使用自定义视频采集时,请确保此函数的值为 "true"。
     * @param {boolean} enable - 是否打开摄像头;"true" 表示打开摄像头;"false" 表示关闭摄像头。
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    enableCamera(enable, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.enableCamera({enable, channel});
    }

    /**
     * 选择使用某个视频设备,支持设置其他通道的推流
     *
     * @param {string} deviceID - 通过 getVideoDeviceList: 获取的某个设备的 ID
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    useVideoDevice(deviceID, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.useVideoDevice({deviceID, channel});
    }

    /**
     * 获取视频设备列表
     *
     * @return {ZegoDeviceInfo[]} - 视频设备列表
     */
    getVideoDeviceList(){
        return this.ZegoNativeInstance.getVideoDeviceList({});
    }

    /**
     * 获取默认视频设备ID
     *
     * @return {string} - 默认视频设备 ID
     */
    getDefaultVideoDeviceID(){
        return this.ZegoNativeInstance.getDefaultVideoDeviceID({});
    }

    /**
     * 启动声浪监控,支持设置监听间隔。
     *
     * 详情描述:启动监控后可通过 [onCapturedSoundLevelUpdate] 回调接收本地采集音频声浪,以及 [onRemoteSoundLevelUpdate] 回调接收远端拉流音频声浪。开发者可在进入房间之前,调用 [startPreview] 与此函数,并与 [onCapturedSoundLevelUpdate] 结合来判断音频设备是否正常工作。
     * 业务场景:在推拉流过程中,判断麦上的用户谁在说话,并做 UI 展示。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 注意事项:[onCapturedSoundLevelUpdate] 与 [onRemoteSoundLevelUpdate] 回调通知周期为参数设置的值,若需要使用声浪进阶功能,请使用同名重载函数(参数类型为 ZegoSoundLevelConfig)代替。
     * @param {number} millisecond - 声浪的监控时间周期,单位为毫秒,取值范围 [100, 3000]。默认 100 ms。
     */
    startSoundLevelMonitor(millisecond = 100){
        this.ZegoNativeInstance.startSoundLevelMonitor({millisecond});
    }

    /**
     * 停止声浪监控。
     *
     * 详情描述:停止监控后将停止回调本地采集以及远端拉流的音频声浪回调。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 相关接口:可通过 [startSoundLevelMonitor] 启动声浪监控。
     */
    stopSoundLevelMonitor(){
        this.ZegoNativeInstance.stopSoundLevelMonitor({});
    }

    /**
     * 启动音频频谱监控,支持设置监听间隔。
     *
     * 详情描述:启动监控后可通过 [onCapturedAudioSpectrumUpdate] 回调接收本地采集音频频谱,以及 [onRemoteAudioSpectrumUpdate] 回调接收远端音频声浪。
     * 业务场景:在主播 K 歌场景中,已经推流或拉流的前提下,让主播或观众看到音调与音量变化的动画。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 注意事项:[onCapturedAudioSpectrumUpdate] 与 [onRemoteAudioSpectrumUpdate] 回调通知周期为参数设置的值。
     * @param {number} millisecond - 音频频谱的监控时间周期,单位为毫秒,取值范围 [100, 3000]。默认 100 ms。
     */
    startAudioSpectrumMonitor(millisecond = 100){
        this.ZegoNativeInstance.startAudioSpectrumMonitor({millisecond});
    }

    /**
     * 停止音频频谱监控。
     *
     * 详情描述:停止监控后将停止回调本地采集以及远端拉流的音频频谱回调。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 相关接口:可通过 [startAudioSpectrumMonitor] 启动音频频谱监控。
     */
    stopAudioSpectrumMonitor(){
        this.ZegoNativeInstance.stopAudioSpectrumMonitor({});
    }

    /**
     * 开启/关闭 耳返。
     *
     * 详情描述:开启耳返,用户使用麦克风采集声音时会听到自己的声音。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 默认值:关闭。
     * 注意事项:同时连接耳机和麦克风时该设置才实际生效。
     * @param {boolean} enable - true: 开启耳返, false: 关闭耳返。
     */
    enableHeadphoneMonitor(enable){
        this.ZegoNativeInstance.enableHeadphoneMonitor({enable});
    }

    /**
     * 设置耳返音量。
     *
     * 详情描述:设置耳返音量。
     * 调用时机:在创建引擎 [initWithProfile/init] 后。
     * 注意事项:同时连接耳机和麦克风时该设置才实际生效。
     * 相关接口:可通过 [enableHeadphoneMonitor] 开关耳返。
     * @param {number} volume - 采集耳返音量大小,取值 [0, 200],默认 100。
     */
    setHeadphoneMonitorVolume(volume){
        this.ZegoNativeInstance.setHeadphoneMonitorVolume({volume});
    }

    /**
     * 开启/关闭系统声卡采集。
     *
     * 详情描述:开启声卡采集,将系统播放的声音混入推流中,如浏览器播放的声音、第三方播放器软件播放的声音等。
     * 默认值:默认关闭。
     * 调用时机:调用 [startPublishingStream] 或 [startPreview] 后调用此函数。
     * 使用限制:无。
     * 注意事项:系统声卡声音不包含拉流声音、媒体播放器声音和音效播放器声音。
     * 相关接口:[setMixSystemPlayoutVolume] 设置系统声卡采集的音量。
     * 平台差异:仅支持 Windows、macOS。
     * @param {boolean} enable - true: 开启声卡采集, false: 关闭声卡采集
     */
    enableMixSystemPlayout(enable){
        this.ZegoNativeInstance.enableMixSystemPlayout({enable});
    }

    /**
     * 获取当前使用的音频设备信息。
     *
     * 详情描述:获取当前使用的音频设备信息。
     * 业务场景:用于需要手动在多个音频设备间切换的场景。
     * 调用时机:调用 [startPublishingStream] 或 [startPreview] 后调用此函数。
     * 相关接口:可通过 [getDefaultAudioDeviceID] 获取默认音频设备 ID。
     * @param {ZegoAudioDeviceType} deviceType - 音频设备类型。是否必填:是。
     * @return {ZegoDeviceInfo} - 音频设备信息。
     */
    getCurrentAudioDevice(deviceType){
        return this.ZegoNativeInstance.getCurrentAudioDevice({deviceType});
    }

    /**
     * 是否开启回声消除。
     *
     * 详情描述:打开回声消除, SDK 会对采集到的音频数据进行过滤以降低音频中的回音成分。
     * 业务场景:当需要降低回声以提高通话质量和用户体验时,可以开启此功能。
     * 默认值:未调用此函数时,默认开启回声消除。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后 ,[startPublishingStream]、 [startPlayingStream]、 [startPreview]、 [createMediaPlayer] 和 [createAudioEffectPlayer] 之前调用。
     * 注意事项:回声消除功能仅支持处理经过 SDK 播放的声音,例如拉流、媒体播放器、音效播放器等功能播放的声音。
     * 使用限制:无。
     * 相关接口:开发者可通过 [enableHeadphoneAEC] 以设置当使用耳机时是否也开启回声消除;可通过 [setAECMode] 设置回声消除的模式。
     * @param {boolean} enable - 是否开启回声消除;true 表示开启;false 表示关闭
     */
    enableAEC(enable){
        this.ZegoNativeInstance.enableAEC({enable});
    }

    /**
     * 设置回声消除模式
     *
     * 详情描述:当使用 [enableAEC] 开启了回声消除后,可通过此函数切换不同的回声消除模式以控制消除回声数据的程度。
     * 业务场景:当默认的回声消除效果不符合预期时,可通过此函数调整回声消除模式。
     * 默认值:未调用此函数时,默认的回声消除模式为 [Aggressive] 激进模式。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后,[startPublishingStream]、 [startPlayingStream]、 [startPreview]、 [createMediaPlayer] 和 [createAudioEffectPlayer] 之前调用。
     * 使用限制:仅在开启了回声消除功能后此函数设置的值才有效。
     * @param {ZegoAECMode} mode - 回声消除模式
     */
    setAECMode(mode){
        this.ZegoNativeInstance.setAECMode({mode});
    }

    /**
     * 开/关自动增益控制
     *
     * 详情描述:开启该功能后,SDK 能够自动调节麦克风音量,适应远近拾音,保持音量稳定。
     * 业务场景:当需要保障音量稳定性以提高通话质量和用户体验时,可以开启此功能。
     * 默认值:未调用此函数时,默认开启自动增益控制。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后,[startPublishingStream]、 [startPlayingStream]、 [startPreview]、 [createMediaPlayer] 和 [createAudioEffectPlayer] 之前调用。注意 Mac 端需要在 [startPreview] 之后,[startPublishingStream] 之前调用。
     * 使用限制:无。
     * @param {boolean} enable - 是否开启自动增益控制;true 表示开启;false 表示关闭
     */
    enableAGC(enable){
        this.ZegoNativeInstance.enableAGC({enable});
    }

    /**
     * 开/关噪声抑制
     *
     * 详情描述:开启该功能后,可以使人声更加清晰。
     * 业务场景:当需要抑制噪声以提高通话质量和用户体验时,可以开启此功能。
     * 默认值:未调用此函数时,默认开启噪声抑制。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后,[startPublishingStream]、 [startPlayingStream]、 [startPreview]、 [createMediaPlayer] 和 [createAudioEffectPlayer] 之前调用。
     * 相关接口:此功能对持续性的噪声(例如下雨声等白噪音)抑制效果较好,如果需要抑制瞬态噪声,请使用 [enableTransientANS];可通过 [setANSMode] 设置噪声抑制的模式。
     * 使用限制:无。
     * @param {boolean} enable - 是否开启噪声抑制;true 表示开启噪声抑制;false 表示关闭噪声抑制
     */
    enableANS(enable){
        this.ZegoNativeInstance.enableANS({enable});
    }

    /**
     * 开/关瞬态噪声抑制
     *
     * 详情描述:用于抑制敲击键盘、桌子等瞬态噪声。
     * 业务场景:当需要抑制瞬态噪声以提高通话质量和用户体验时,可以开启此功能。
     * 默认值:未调用此函数时,默认不开启瞬态噪声抑制。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后,[startPublishingStream]、 [startPlayingStream]、 [startPreview]、 [createMediaPlayer] 和 [createAudioEffectPlayer] 之前调用。
     * 相关接口:此函数开启后不会抑制常规噪声,如果需要开启常规噪声抑制,请使用 [enableANS]
     * 使用限制:无。
     * @param {boolean} enable - 是否开启瞬态噪声抑制;true 表示开启;false 表示关闭
     */
    enableTransientANS(enable){
        this.ZegoNativeInstance.enableTransientANS({enable});
    }

    /**
     * 设置音频噪声抑制模式
     *
     * 详情描述:当使用 [enableANS] 开启了噪声抑制后,可通过此函数切换不同的噪声抑制模式以控制抑制噪声数据的程度。
     * 业务场景:当默认的噪声抑制效果不符合预期时,可通过此函数调整噪声抑制模式。
     * 默认值:未调用此函数时,默认的回声消除模式为 [Medium] 中等模式。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后,[startPublishingStream]、 [startPlayingStream]、 [startPreview]、 [createMediaPlayer] 和 [createAudioEffectPlayer] 之前调用。
     * 使用限制:仅在开启了噪声抑制功能后此函数设置的值才有效。
     * @param {ZegoANSMode} mode - 噪声抑制模式
     */
    setANSMode(mode){
        this.ZegoNativeInstance.setANSMode({mode});
    }

    /**
     * 设置音效均衡器(EQ)。
     *
     * 详情描述:可通过调用本函数设置音效均衡器调整音色。
     * 业务场景:通常用于语聊房、KTV 等场景。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后调用才有效。
     * 使用限制:无。
     * @param {number} bandIndex - 频谱子带索引,取值范围 [0, 9],分别对应 10 个频带,中心频率分别是 [31, 62, 125, 250, 500, 1K, 2K, 4K, 8K, 16K] Hz。
     * @param {number} bandGain - 指定频带的增益值,取值范围 [-15, 15],默认值为 0,如果所有频带的增益值全部为 0,即关闭 EQ 功能。
     */
    setAudioEqualizerGain(bandIndex, bandGain){
        this.ZegoNativeInstance.setAudioEqualizerGain({bandIndex, bandGain});
    }

    /**
     * 通过预设枚举设置变声。
     *
     * 详情描述:可通过调用本函数设置预设变声效果。
     * 业务场景:通常用于直播、语聊房和 KTV 等场景。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后调用才有效。
     * 使用限制:如果使用自定义音频采集,变声会失效。
     * 相关接口:
     * 如需自定义变声效果,可使用 [setVoiceChangerParam]。
     * 本函数与 [setReverbPreset] 互斥,同时使用会产生未定义的效果。
     * 使用机器人或空灵预设变声效果时,会修改混响或混响回声参数。因此,在使用上述预设变声效果后调用 [setVoiceChangerParam], [setReverbAdvancedParam], [setReverbEchoParam] 等函数可能影响变声效果。
     * 如需自定义混响/回声/变声/电音效果可通过 [setReverbAdvancedParam], [setReverbEchoParam], [setVoiceChangerParam], [setElectronicEffects] 四个函数组合配置使用。
     * @param {ZegoVoiceChangerPreset} preset - 变声预设枚举。
     */
    setVoiceChangerPreset(preset){
        this.ZegoNativeInstance.setVoiceChangerPreset({preset});
    }

    /**
     * 设置变声的具体参数。
     *
     * 详情描述:可通过调用本函数设置自定义变声效果。
     * 业务场景:通常用于直播、语聊房和 KTV 等场景。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后调用才有效。
     * 使用限制:如果使用自定义音频采集,变声会失效。
     * 相关接口:
     * 如需使用常见的变声效果,可使用 [setVoiceChangerPreset] 函数。
     * 如需自定义混响/回声/变声效果可通过 [setReverbAdvancedParam], [setReverbEchoParam], [setVoiceChangerParam] 三个函数组合配置使用。
     * @param {ZegoVoiceChangerParam} param - 变声参数。
     */
    setVoiceChangerParam(param){
        this.ZegoNativeInstance.setVoiceChangerParam({param});
    }

    /**
     * 通过预设枚举设置混响。
     *
     * 详情描述:可通过调用本函数设置预设混响效果。
     * 业务场景:通常用于直播、语聊房和 KTV 等场景。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后调用才有效。支持推流过程中调用本函数动态设置混响效果。
     * 使用限制:如果使用自定义音频采集,混响会失效。
     * 相关接口:
     * 如需自定义混响效果,请使用 [setReverbAdvancedParam]。
     * 本函数与 [setVoiceChangerPreset] 互斥,同时使用将产生未定义的效果。
     * 如需自定义混响/回声/变声效果可通过 [setReverbAdvancedParam], [setReverbEchoParam], [setVoiceChangerParam] 三个函数组合配置使用。
     * @param {ZegoReverbPreset} preset - 混响预设枚举。
     */
    setReverbPreset(preset){
        this.ZegoNativeInstance.setReverbPreset({preset});
    }

    /**
     * 设置混响的具体参数。
     *
     * 详情描述:可通过调用本函数设置自定义混响效果。
     * 业务场景:通常用于直播、语聊房和 KTV 等场景。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后调用才有效。
     * 使用限制:如果使用自定义音频采集,混响会失效。
     * 注意事项:推流过程中动态设置不同的值都会生效,当全部参数都设置成 0 时,混响关闭。
     * 相关接口:
     * 如需使用常见的混响效果,可使用 [setReverbPreset] 函数。
     * 如需自定义混响/回声/变声效果可通过 [setReverbAdvancedParam], [setReverbEchoParam], [setVoiceChangerParam] 三个函数组合配置使用。
     * @param {ZegoReverbAdvancedParam} param - 混响高级参数。
     */
    setReverbAdvancedParam(param){
        this.ZegoNativeInstance.setReverbAdvancedParam({param});
    }

    /**
     * 设置混响回声效果的具体参数。
     *
     * 详情描述:可通过调用本函数设置混响回声效果。可搭配变声、混响以实现自定义各式各样的声音效果。
     * 业务场景:通常用于直播、语聊房和 KTV 等场景。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后调用才有效。
     * 使用限制:如果使用自定义音频采集,混响回声将失效。
     * 相关接口:如需自行配置混响/回声/变声效果请通过 [setReverbAdvancedParam], [setReverbEchoParam], [setVoiceChangerParam] 三个函数组合使用。
     * @param {ZegoReverbEchoParam} param - 混响回声效果参数。
     */
    setReverbEchoParam(param){
        this.ZegoNativeInstance.setReverbEchoParam({param});
    }

    /**
     * 开启推流时带虚拟立体声效果。
     *
     * 详情描述:可通过调用本函数开启/关闭推流时带虚拟立体声效果。
     * 业务场景:通常用于直播、语聊房和 KTV 等场景。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后调用才有效。
     * 使用限制:如果使用自定义音频采集,虚拟立体声将失效。
     * 注意事项:需要调用 [setAudioConfig] 设置双声道后虚拟立体声才能生效。
     * @param {boolean} enable - true 代表开启虚拟立体声,false 代表关闭虚拟立体声。
     * @param {number} angle - 虚拟立体声中声源的角度,范围为 0~180,90 为正前方,0 和 180 分别对应最右边和最左边,一般可使用 90。
     */
    enableVirtualStereo(enable, angle){
        this.ZegoNativeInstance.enableVirtualStereo({enable, angle});
    }

    /**
     * 发送房间广播消息。
     *
     * 详情描述:向房间发送广播消息,已经登录相同房间的用户能收到消息,消息可靠。
     * 业务场景:一般在直播房间人数不超过 500 时使用。
     * 调用时机:调用 [loginRoom] 登录房间之后。
     * 使用限制:房间在线人数超过 500 时不支持,如果需要提高限制,请联系 ZEGO 技术支持申请评估。同一房间内的广播消息发送频率不能高于 10条/s。单个用户在客户端调用此接口的最大QPS为2,关于此函数的使用限制,请参考 https://doc-zh.zego.im/article/7581 或联系 ZEGO 技术支持。
     * 相关回调:可通过 [onIMRecvBroadcastMessage] 接收到房间广播消息。
     * 相关接口:可通过 [sendBarrageMessage] 函数发送弹幕消息,可通过 [sendCustomCommand] 函数发送自定义信令。
     * @param {string} roomID - 房间 ID。是否必填:是。取值范围:最大长度为 128 字节。注意事项:房间 ID 为字符串格式,仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'。
     * @param {string} message - 消息内容。是否必填:是。取值范围:长度不超过 1024 字节。
     * @return {Promise<number, number>} - 发送广播消息结果通知。是否必填:否。注意事项:传 [null] 则意味着不接收回调通知。
     */
    sendBroadcastMessage(roomID, message){
        return this.ZegoNativeInstance.sendBroadcastMessage({roomID, message});
    }

    /**
     * 发送房间弹幕消息。
     *
     * 详情描述:向房间发送弹幕消息,已经登录相同房间的用户能收到消息,消息不可靠。
     * 业务场景:一般用于房间内有大量消息收发,且不需要保证消息可靠性的场景,例如直播弹幕。
     * 调用时机:调用 [loginRoom] 登录房间之后。
     * 使用限制:同一房间内的弹幕消息发送频率不能高于 20条/s。关于此函数的使用限制,请参考 https://doc-zh.zego.im/article/7581 或联系 ZEGO 技术支持。
     * 相关回调:可通过 [onIMRecvBarrageMessage] 接收到房间弹幕消息。
     * 相关接口:可通过 [sendBroadcastMessage] 函数发送广播消息,可通过 [sendCustomCommand] 函数发送自定义信令。
     * @param {string} roomID - 房间 ID。是否必填:是。取值范围:最大长度为 128 字节。注意事项:房间 ID 为字符串格式,仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'。
     * @param {string} message - 消息内容。是否必填:是。取值范围:长度不超过 1024 字节。
     * @return {Promise<number, string>} - 发送弹幕消息结果通知。
     */
    sendBarrageMessage(roomID, message){
        return this.ZegoNativeInstance.sendBarrageMessage({roomID, message});
    }

    /**
     * 发送自定义信令。
     *
     * 详情描述:向已经登录相同房间的其他用户发送点对点的信令,消息可靠。
     * 业务场景:一般用于远程控制信令或用户与用户之间的消息发送。
     * 调用时机:调用 [loginRoom] 登录房间之后。
     * 使用限制:一般在直播房间人数不超过 500 时使用。同一房间内向单个用户发送的自定义消息频率不能高于 200条/s,向多个用户发送的自定义消息不能高于 10条/s。关于此函数的使用限制,请参考 https://doc-zh.zego.im/article/7581 或联系 ZEGO 技术支持。
     * 相关回调:可通过 [onIMRecvCustomCommand] 接收到房间自定义信令。
     * 相关接口:可通过 [sendBroadcastMessage] 函数发送广播消息,可通过 [sendBarrageMessage] 函数发送弹幕消息。
     * 隐私保护声明:请勿在此接口填写用户敏感信息,包括但不限于手机号、身份证号、护照编号、真实姓名等。
     * @param {string} roomID - 房间 ID。是否必填:是。取值范围:最大长度为 128 字节。注意事项:房间 ID 为字符串格式,仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'。
     * @param {string} command - 自定义信令内容。是否必填:是。取值范围:最大长度为 1024 字节。注意事项:为保护隐私,请勿在此接口填写用户敏感信息,包括但不限于手机号、身份证号、护照编号、真实姓名等。
     * @param {ZegoUser[]} toUserList - 信令的接收者列表。是否必填:是。取值范围:用户列表或者 [null]。注意事项:为 [null] 时 SDK 回向房间内所有用户发送自定义信令。
     * @return {Promise<number>} - 发送信令结果通知。
     */
    sendCustomCommand(roomID, command, toUserList){
        return this.ZegoNativeInstance.sendCustomCommand({roomID, command, toUserList});
    }

    /**
     * 创建媒体播放器实例对象。
     *
     * 详情描述:创建媒体播放器实例对象。
     * 业务场景:常用于播放媒体资源场景,例如播放视频文件,结合自定义视频采集将媒体资源的视频数据推送出去,远端可拉流观看。
     * 调用时机:在 [initWithProfile/init] 初始化 SDK 之后。
     * 使用限制:目前最多支持创建 4 个实例,超过后将返回 null。
     * 注意事项:媒体播放器的实例越多,对设备的性能开销越大。
     * 相关接口:用户可以调用 [destroyMediaPlayer] 销毁媒体播放器实例对象。
     * @return {ZegoMediaPlayer} - 媒体播放器实例,超过最大数量限制后将返回 null。
     */
    createMediaPlayer(){
        let mediaPlayer = null;
        let nativeMediaPlayer = this.ZegoNativeInstance.createMediaPlayer();
        if(nativeMediaPlayer){
            mediaPlayer = new ZegoMediaPlayer()
            mediaPlayer.nativeMediaPlayer = nativeMediaPlayer;
            let nativeMediaPlayerPtr = mediaPlayer.nativeMediaPlayer.getNativePtr();
            this.mediaPlayers[nativeMediaPlayerPtr] = mediaPlayer
        }
        return mediaPlayer;
    }

    /**
     * 销毁媒体播放器实例对象。
     *
     * 详情描述:销毁媒体播放器实例对象。
     * 相关接口:用户可以调用 [createMediaPlayer] 创建媒体播放器实例对象。
     * @param {ZegoMediaPlayer} mediaPlayer - 媒体播放器实例对象。
     */
    destroyMediaPlayer(mediaPlayer){
        let nativeMediaPlayer = mediaPlayer.nativeMediaPlayer;
        let nativeMediaPlayerPtr = mediaPlayer.nativeMediaPlayer.getNativePtr();
        this.ZegoNativeInstance.destroyMediaPlayer({ nativeMediaPlayer});
        this.mediaPlayers[nativeMediaPlayerPtr] = null;
    }

    /**
     * 开始本地录制,直接将音视频数据录制到本地文件。
     *
     * 详情描述:开始录制本端音频或音视频,直接将音视频数据录制到本地文件,录制的数据将与该通道推流的数据一致。
     * 调用时机:此函数需要调用 [startPreview] 或 [startPublishingStream] 成功之后再调用才有效。
     * 使用限制:无。
     * 注意事项:录制过程中不可以停止预览 [stopPreview] 或停止推流 [stopPublishingStream],否则 SDK 将主动结束当前录制任务。媒体播放器的数据需要混入到推流中才能录制。
     * 相关回调:开始录制后将会收到 [onCapturedDataRecordStateUpdate] 录制状态回调和 [onCapturedDataRecordProgressUpdate] 录制进度回调。
     * @param {ZegoDataRecordConfig} config - 录制配置对象。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    startRecordingCapturedData(config, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.startRecordingCapturedData({config, channel});
    }

    /**
     * 结束录制本端音频或音视频。
     *
     * 详情描述:结束录制本端音频或音视频。
     * 调用时机:在 [startRecordingCapturedData] 之后。
     * 使用限制:无。
     * @param {ZegoPublishChannel} channel - 推流通道。
     */
    stopRecordingCapturedData(channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.stopRecordingCapturedData({channel});
    }

    /**
     * 启动网络测速,支持设置测速周期。
     *
     * 详情描述:支持上行/下行网络测速。
     * 业务场景:用于检测当前网络环境是否适合推/拉指定码率的流。
     * 调用时机:需要在 [initWithProfile/init] 之后,[startPublishingStream] 之前调用。若在测速中途开始推流,则测速会自动停止。
     * 使用限制:无。
     * 注意事项:可监听 [onNetworkSpeedTestQualityUpdate] 回调来获取测速结果,每 3 秒回调一次结果。若测速过程中发生异常,将会触发 [onNetworkSpeedTestError] 回调。若重复多次调用本函数,将以最后一次调用的测速配置为准。
     * 相关接口:可通过 [stopNetworkSpeedTest] 停止网络测速。
     * @param {ZegoNetworkSpeedTestConfig} config - 网络测速度配置。
     */
    startNetworkSpeedTest(config){
        this.ZegoNativeInstance.startNetworkSpeedTest({config});
    }

    /**
     * 停止网络测速。
     *
     * 详情描述:停止网络测速。
     * 业务场景:用于检测当前网络环境是否适合推/拉指定码率的流。
     * 调用时机:需要在 [initWithProfile/init] 初始化 SDK 之后调用。
     * 使用限制:无。
     * 注意事项:停止网络测速后,将不再触发 [onNetworkSpeedTestQualityUpdate] 回调。
     * 相关接口:可通过 [startNetworkSpeedTest] 启动网络测速。
     */
    stopNetworkSpeedTest(){
        this.ZegoNativeInstance.stopNetworkSpeedTest({});
    }

    /**
     * 开始或停止自定义视频采集,支持设置其他通道的推流。
     *
     * 详情描述:enable 为 "true" 时开启视频自定义采集,为 "false" 时关闭视频自定义采集。
     * 业务场景:开发者开发的 App使用了第三方美颜厂商的美颜 SDK,直播非摄像头采集的数据等。
     * 默认值:没有调用该函数时,默认关闭自定义视频采集。
     * 调用时机:在 [initWithProfile/init] 初始化 SDK 之后,调用 [startPreview]、[startPublishingStream] 之前。如果需要修改配置,请先调用 [logoutRoom] 登出房间。
     * 注意事项:自定义视频渲染功能可以与自定义视频采集功能同时使用,但当两者同时开启时,自定义视频渲染的本地采集帧回调将不会再被触发,开发者应该直接在自定义视频采集源里直接获取采集视频帧。
     * 相关回调:当开发者开启自定义采集时,通过调用 [setCustomVideoCaptureHandler] 可设置接收自定义采集启停事件通知。
     * @param {boolean} enable - 是否开启
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    enableCustomVideoCapture(enable, channel){
        this.ZegoNativeInstance.enableCustomVideoCapture({enable, channel});
    }

    /**
     * 注册自定义视频采集插件
     *
     * @param {Number} plugin - 视频采集插件
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    registerCustomVideoCapturePlugin(plugin, channel){
        this.ZegoNativeInstance.registerCustomVideoCapturePlugin({plugin, channel});
    }

    /**
     * 注销自定义视频采集插件。
     *
     * @param {Number} plugin - 视频采集插件
     */
    unregisterCustomVideoCapturePlugin(plugin){
        this.ZegoNativeInstance.unregisterCustomVideoCapturePlugin({plugin});
    }

    /**
     * 初始化引擎
     *
     * 在调用其他函数前需要先创建并初始化引擎
     * @param {number} appID - ZEGO 为开发者签发的应用 ID,请从 ZEGO 管理控制台 https://console-express.zego.im 申请。appID 取值范围 0~4294967295。
     * @param {string} appSign - 每个 AppID 对应的应用签名,请从 ZEGO 管理控制台申请。该参数为包含 64 个字符的字符串,字符取值范围:'0' ~ '9', 'a' ~ 'z'。例:"9dc9a25bh2f2137446897071c8c033fa33b91c3dd2a85e0c000ae82c0dad3"。
     * @param {boolean} isTestEnv - 选择使用测试环境还是正式商用环境,正式环境需要在 ZEGO 管理控制台提交工单配置。测试环境为测试开发用,房间数并发上限为 10 ,单房间用户数上限为 50。正式环境 App 正式上线用,ZEGO 会根据开发者在管理控制台提交的配置记录提供相应的服务资源。测试环境与正式环境是两套环境,不可互通。
     * @param {ZegoScenario} scenario - 产品的应用场景,开发者可根据所开发的 App 的场景选择其中一个,SDK 会针对该场景的作一些优化。当设置具体场景后,开发者若需要定制化更多参数,依然可以调用具体函数来设置具体参数。不同应用场景的建议配置可以参考:https://doc-zh.zego.im/faq/profile_difference。
     * @deprecated 此函数在 0.25.3 版本及以上已废弃,请使用不带 [isTestEnv] 参数的函数 [initWithProfile] 代替。
     */
    init(appID, appSign, isTestEnv, scenario){
        let tsfn = this.callEmit.bind(this);
        const that = this;
        that.isConsolePrintDebugInfo = isTestEnv;
        that.appID = appID;

        //get electron sdk version
        var SdkVersion = this.getVersion();

        return new Promise(function (resolve, reject) {
            that.ZegoNativeInstance = ZegoNativeSDK.CreateEngine({ appID, appSign, isTestEnv, scenario, tsfn, SdkVersion})
            if (that.ZegoNativeInstance === undefined) {
                reject("Zego Express init failed");
            }
            else {
                that.VideoViewManager = {
                    localGLRenders: [],
                    remoteGLRenders: []
                };
                that.mediaPlayers = [];
                console.log("Zego Express init succeed");
                resolve();
            };
        });
    }
    
    /**
     * 开始或停止自定义视频前处理,支持设置其他通道的推流.
     *
     * 当开发者开启自定义处理前,通过调用 [setCustomVideoCaptureHandler] 可以设置接收自定义视频前处理的原始视频数据。
     * 前提条件:在[initWithProfile/init] 初始化 SDK 之后
     * 调用时机:必须在调用 [startPreview]、[startPublishingStream] 之前设置; 在调用 [logoutRoom] 之前不能再次更改配置,否则调用不会生效。
     * @param {boolean} enable - 是否开启
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    enableCustomVideoProcess(enable, channel){
        this.ZegoNativeInstance.enableCustomVideoProcess({enable, channel});
    }

	/**
     * 注册自定义视频前处理插件
     *
     * @param {Number} plugin - 视频前处理插件
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    registerCustomVideoProcessPlugin(plugin, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.registerCustomVideoProcessPlugin({plugin, channel});
    }

    /**
     * 设置自定义视频处理剪切区域
     *
     * @param {Number} left - 左切割长度 (px)
     * @param {Number} top - 上切割长度 (px)
     * @param {Number} right - 右切割长度 (px)
     * @param {Number} bottom - 下切割长度 (px)
     * @param {ZegoPublishChannel} channel - 推流通道
     */
    setCustomVideoProcessCutRegion(left, top, right, bottom, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.setCustomVideoProcessCutRegion({left, top, right, bottom, channel});
    }
    
    /**
     * 设置播放视频流类型。
     *
     * 详情描述:当推流方通过 [setVideoConfig] 设置了 codecID 为 SVC 时,拉流方可以动态设置选用不同的流类型(小分辨率为标准图层的二分之一)。
     * 业务场景:一般情况下,在网络较弱或者渲染的 UI 窗体较小的情况下,可以选择使用拉取小分辨率的视频来达到节省带宽的目的。
     * 调用时机:在 [initWithProfile/init] 初始化 SDK 后可调用。
     * 使用限制:无。
     * @param {string} streamID - 流 ID。
     * @param {ZegoVideoStreamType} streamType - 视频流类型。
     */
    setPlayStreamVideoType(streamID, streamType){
        this.ZegoNativeInstance.setPlayStreamVideoType({streamID, streamType});
    }

    /**
     * 设置触发流量控制的关注因素。
     *
     * 详情描述:通过该接口控制是否因为远端网络状况差而启动流量控制。
     * 默认值:默认关闭。
     * 调用时机:在创建引擎 [initWithProfile/init] 后,在推流 [startPublishingStream] 前调用生效。
     * 使用限制:必须开启流量控制 [enableTrafficControl]。
     * 注意事项:作用于主推流通道 ZegoPublishChannel.Main。
     * 相关接口:[enableTrafficControl]。
     * @param {ZegoTrafficControlFocusOnMode} mode - 选择 LOCAL_ONLY 时,只关注本地网络状况。选择 REMOTE 时,不仅关注本地网络,同时也兼顾远端网络。
     */
    setTrafficControlFocusOn(mode, channel = ZegoPublishChannel.Main){
        this.ZegoNativeInstance.setTrafficControlFocusOn({mode, channel});
    }
    /**
     * @event ZegoExpressEngine#onDebugError
     * @desc 调试错误信息回调。
     *
     * 详情描述:调用 SDK 函数出现异常时,会通过该回调提示详细的异常信息。
     * 业务场景:开发者在集成 SDK 的开发、测试阶段,可以通过本回调中的详细异常信息快速定位问题。
     * 通知时机:在 SDK 出现异常时通知开发者。
     * 使用限制:无。
     * 注意事项:无。
     * @property {object} result - 结果数据对象
     * @property {number} result.errorCode - 错误码,详情请参考 常见错误码文档 https://doc-zh.zego.im/zh/4378.html。
     * @property {string} result.funcName - 函数名。
     * @property {string} result.info - 错误的详细信息。
     */

    /**
     * @event ZegoExpressEngine#onEngineStateUpdate
     * @desc 音视频引擎状态更新的回调通知。
     *
     * 详情描述:音视频引擎状态更新的回调通知,当启用音视频功能时,比如预览、推流、本地媒体播放器、原始音频数据获取等,音视频引擎会进入开始状态,当退出房间或停用所有音视频功能时,音视频引擎会进入停止状态。
     * 通知时机:开发者调用了相关函数改变了音视频引擎的状态。例如:1. 调用了ZegoExpressEngine的 [startPreview]、[stopPreview]、[startPublishingStream]、[startPlayingStream]、[startAudioDataObserver] 等函数。2. 调用了 MediaPlayer 的相关函数等。3. 调用了 [logoutRoom] 函数。
     * 使用限制:无。
     * 注意事项:1. 开发者调用 [destroyEngine] 时,由于 SDK 的资源被完全释放,并不会触发此通知。2. 如无特殊需要,开发者可以不必关注本回调。
     * @property {object} result - 结果数据对象
     * @property {ZegoEngineState} result.state - 音视频引擎状态。
     */

    /**
     * @event ZegoExpressEngine#onRoomStateUpdate
     * @desc 房间状态变化通知
     *
     * 详情描述:当房间的连接状态改变时触发该回调,并通知改变的原因。
     * 业务场景:开发者可以通过这个回调来判断房间内当前用户的状态。
     * 通知时机:1. 开发者调用 [loginRoom]、[logoutRoom]、[switchRoom] 函数时会收到此通知。2. 用户设备的网络情况变化时也可能收到此通知 (SDK 在断线时会自动重新登录房间,详情请参考 https://doc-zh.zego.im/faq/reconnect )。
     * 使用限制:无。
     * 注意事项:若长时间处于正在请求连接状态(ZegoRoomStateConnecting),一般是因为用户端网络不稳定导致。
     * 相关接口:[loginRoom]、[logoutRoom]、[switchRoom]。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 房间 ID,最大长度为 128 字节的字符串。
     * @property {ZegoRoomState} result.state - 变化后的的房间状态
     * @property {number} result.errorCode - 错误码,详情请参考常用 错误码文档 https://doc-zh.zego.im/zh/4378.html
     * @property {string} result.extendedData - 状态更新附带的扩展信息。当房间登录成功时,可通过"room_session_id" key 获取每一次音视频通信唯一的 RoomSessionID,标识房间内首个用户发起音视频通信到最后一个用户结束通信的持续通信。可用于通话质量评分、通话问题诊断等场景中。
     */

    /**
     * @event ZegoExpressEngine#onRoomUserUpdate
     * @desc 房间内其他用户增加或减少的回调通知。
     *
     * 详情描述:当房间内有其他用户上线或下线时,导致房间内用户列表发生变化,会通过本回调通知开发者。
     * 业务场景:开发者可以通过这个回调来实时更新房间内的用户列表展示。
     * 通知时机:1. 用户首次登录房间时,如果房间内有其他用户,SDK 会触发 "updateType" 为 [ZegoUpdateTypeAdd] 的回调通知,此时 "userList" 为房间内的其他用户。2. 用户已在房间内,如果有其他用户通过 [loginRoom]、[switchRoom] 函数登录到本房间,SDK 会触发 "updateType" 为 [ZegoUpdateTypeAdd] 的回调通知。3. 用户已在房间内,有其他用户通过 [logoutRoom]、[switchRoom] 函数登出本房间,SDK 会触发 "updateType" 为 [ZegoUpdateTypeDelete] 的回调通知。4. 用户已在房间内,如果有其他用户从服务端被踢出本房间,SDK 会触发 "updateType" 为 [ZegoUpdateTypeDelete] 的回调通知。
     * 使用限制:调用 [loginRoom] 登录房间时设置 [ZegoRoomConfig] 参数中的 "isUserStatusNotify" 属性为 "true" 时,才会接收到这个回调通知。如果开发者需要使用在回调通知中处理相关业务,请确保每个登录的用户都将 "isUserStatusNotify" 设置为 "true"。
     * 相关接口:[loginRoom]、[logoutRoom]、[switchRoom]。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 用户已登录的房间 ID,最大长度为 128 字节的字符串。
     * @property {ZegoUpdateType} result.updateType - 更新类型(添加/删除)。
     * @property {ZegoUser[]} result.userList - 当前房间内变更的用户列表。
     */

    /**
     * @event ZegoExpressEngine#onRoomOnlineUserCountUpdate
     * @desc 房间内当前在线用户数量回调。
     *
     * 详情描述:此方法会通知用户当前房间内的在线人数。
     * 业务场景:开发者可根据此回调来来展示当前房间内的在线人数。
     * 通知时机:登录房间成功后。
     * 使用限制:无。
     * 注意事项:1. 此函数 30 秒回调一次。2. 因设计如此,当房间内用户超过 500 后,对房间内在线人数的统计会有一些误差。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 用户已登录的房间 ID,最大长度为 128 字节的字符串。
     * @property {number} result.count - 当前在线用户数量。
     */

    /**
     * @event ZegoExpressEngine#onRoomStreamUpdate
     * @desc 相同房间内其他用户推的流增加或减少的通知。
     *
     * 详情描述:当房间内有其他用户发开始流或停止推流时,导致房间内流列表发生变化,会通过本回调通知开发者。
     * 业务场景:开发者可根据此回调来判断指定房间内其他用户是否新增推流或停止推流,并根据情况选择调用 [startPlayingStream] 主动拉流或调用[stopPlayingStream] 停止拉流,同时也可以变更拉流的 UI 控件。
     * 通知时机:1. 用户首次登录房间时,如果房间内其他用户正在推流,SDK 会触发 updateType 为 [ZegoUpdateTypeAdd] 的回调通知,此时 "streamList" 为已存在的流列表。2. 用户已在房间内,如果有其他用户新增推流,SDK 会触发 "updateType" 为 [ZegoUpdateTypeAdd] 的回调通知。3. 用户已在房间内,如果有其他用户停止推流,SDK 会触发 "updateType" 为 [ZegoUpdateTypeDelete] 的回调通知。4. 用户已在房间内,如果有其他用户退出房间,SDK 会触发 "updateType" 为 [ZegoUpdateTypeDelete] 的回调通知。
     * 使用限制:无。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 用户已登录的房间 ID,最大长度为 128 字节的字符串。
     * @property {ZegoUpdateType} result.updateType - 更新类型(添加/删除)。
     * @property {ZegoStream[]} result.streamList - 更新的流列表。
     * @property {string} result.extendedData - 流更新附带的扩展信息。
     */

    /**
     * @event ZegoExpressEngine#onRoomStreamExtraInfoUpdate
     * @desc 房间内流附加信息更新通知。
     *
     * 详情描述:房间内流附加信息更新时所有房间内用户会收到通知。
     * 业务场景:用户可通过流附加信息与流生命周期一致的特性实现一些业务功能。
     * 通知时机:当相同房间内一个正在推流的用户更新了流的附加信息时,相同房间内的其他用户会收到该回调。
     * 使用限制:无。
     * 注意事项:不同于流 ID 在推流过程中不可修改,流附加信息可以在对应流 ID 的生命周期中更新。
     * 相关接口:推流用户可以通过 [setStreamExtraInfo] 设置流附加信息。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 用户已登录的房间 ID,最大长度为 128 字节的字符串。
     * @property {ZegoStream[]} result.streamList - 流附加信息更新的流列表。
     */

    /**
     * @event ZegoExpressEngine#onRoomExtraInfoUpdate
     * @desc 房间附加信息更新通知。
     *
     * 详情描述:房间附加信息更新后,除更新房间附加信息的用户外,房间内所有用户会收到通知。
     * 业务场景:为房间附加信息。
     * 通知时机:当相同房间内其他用户更新了房间附加信息时,相同房间内的其他用户会收到该回调。
     * 使用限制:无。
     * 相关接口:用户可以通过 [setRoomExtraInfo] 更新房间附加信息。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 用户已登录的房间 ID,最大长度为 128 字节的字符串。
     * @property {ZegoRoomExtraInfo[]} result.roomExtraInfoList - 更新的房间附加信息列表。
     */

    /**
     * @event ZegoExpressEngine#onPublisherStateUpdate
     * @desc 推流状态回调。
     *
     * 详情描述:在调用推流接口 [startPublishingStream] 成功后,可以通过该回调函数获取推流状态变更的通知。开发者可根据 state 参数是否在 [正在请求推流状态] 来大体判断用户的推流网络情况。
     * 注意事项:参数 [extendedData] 为状态更新附带的扩展信息。若使用 ZEGO 的 CDN 内容分发网络,在推流成功后,该参数的内容的键为 [flv_url_list]、[rtmp_url_list]、[hls_url_list],分别对应 flv、rtmp、hls 协议的拉流 URL。
     * 相关回调:在调用拉流接口 [startPlayingStream] 成功后,可以通过回调函数 [onPlayerStateUpdate] 获取拉流状态变更的通知。开发者可根据 state 参数是否在 [正在请求拉流状态] 来大体判断用户的拉流网络情况。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 推流的流 ID。
     * @property {ZegoPublisherState} result.state - 推流状态。
     * @property {number} result.errorCode - 推流状态变更对应的错误码。请参考 常见错误码文档 https://doc-zh.zego.im/zh/4378.html
     * @property {string} result.extendedData - 状态更新附带的扩展信息。
     */

    /**
     * @event ZegoExpressEngine#onPublisherQualityUpdate
     * @desc 推流质量回调。
     *
     * 详情描述:在调用推流接口 [startPublishingStream] 成功后默认3秒(该时间如果需要变更,请联系 ZEGO 技术支持配置)会收到此回调,通过该回调可以获取推送的音视频流的采集帧率,码率,RTT,丢包率等质量数据。开发者可根据此函数的质量参数实时监控推送的音视频流的健康情况,以便在设备 UI 界面上实时展示上行网络状况。
     * 注意事项:若开发者不清楚该回调函数的各个参数应该如何使用,可以只关注其中的 [quality] 参数的 [level] 字段,这是 SDK 内部根据质量参数计算的一个描述上行网络的综合值。
     * 相关回调:当调用拉流接口 [startPlayingStream] 成功后每3秒会收到回调 [onPlayerQualityUpdate],开发者可根据拉取的音视频流的帧率,码率,RTT,丢包率等质量数据,实时监控拉取流的健康情况。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 推流的流 ID。
     * @property {ZegoPublishStreamQuality} result.quality - 推流质量,包含了音视频帧率、码率、RTT 等值。
     */

    /**
     * @event ZegoExpressEngine#onPublisherCapturedAudioFirstFrame
     * @desc 推流端音频采集首帧回调。
     *
     * 详情描述:调用推流函数 [startPublishingStream] 成功后,SDK 采集到第一帧音频数据时会收到此回调。开发者可根据该回调判断 SDK 是否真的采集到音频数据,若未收到该回调,说明音频采集设备被占用或异常。
     * 通知时机:在未推流 [startPublishingStream] 或未预览 [startPreview] 的情况下,首次推流或首次预览,即 SDK 内部的音视频模块的引擎启动时,会去采集本机设备的音频数据,会收到该回调。
     * 相关回调:调用推流函数 [startPublishingStream] 成功后, 通过回调函数 [onPublisherCapturedVideoFirstFrame] 判断 SDK 是否真的采集到视频数据,通过回调 [onPublisherRenderVideoFirstFrame] 判断 SDK 是否渲染完采集到的第一帧视频数据。
     * @property {object} result - 结果数据对象
     */

    /**
     * @event ZegoExpressEngine#onPublisherCapturedVideoFirstFrame
     * @desc 推流端视频采集首帧回调。
     *
     * 详情描述:调用推流函数 [startPublishingStream] 成功后,SDK 采集到第一帧视频数据时会收到此回调。开发者可根据该回调判断 SDK 是否真的采集到视频数据,若未收到该回调,说明视频采集设备被占用或异常。
     * 通知时机:在未推流 [startPublishingStream] 或未预览 [startPreview] 的情况下,首次推流或首次预览,即 SDK 内部的音视频模块的引擎启动时,会去采集本机设备的视频数据,会收到该回调。
     * 相关回调:调用推流函数 [startPublishingStream] 成功后, 通过回调函数 [onPublisherCapturedAudioFirstFrame] 判断 SDK 是否真的采集到音频数据,通过回调 [onPublisherRenderVideoFirstFrame] 判断 SDK 是否渲染完采集到的第一帧视频数据。
     * @property {object} result - 结果数据对象
     * @property {ZegoPublishChannel} result.channel - 推流通道,如果只推一路音视频流,可以不关注该参数。
     */

    /**
     * @event ZegoExpressEngine#onPublisherVideoSizeChanged
     * @desc 采集视频大小变更回调。
     *
     * 详情描述:当在未推流 [startPublishingStream] 或未预览 [startPreview] 的情况下,首次推流或首次预览,即 SDK 内部的音视频模块的引擎启动时,会去采集本机设备的视频数据,此时采集分辨率会改变。
     * 通知时机:推流 [startPublishingStream] 成功后,在推流中途如果有改变视频采集分辨率发生变化将会收到此回调。
     * 业务场景:开发者可以根据此回调来去除本地预览的 UI 的遮盖等类似操作。也可以根据该回调的分辨率来动态调整预览视图的比例等。
     * 注意事项:外部采集时通知的是编码分辨率大小变化,会受到流控影响。
     * @property {object} result - 结果数据对象
     * @property {number} result.width - 视频采集分辨率宽。
     * @property {number} result.height - 视频采集分辨率高。
     * @property {ZegoPublishChannel} result.channel - 推流通道,如果只推一路音视频流,可以不关注该参数。
     */

    /**
     * @event ZegoExpressEngine#onPublisherRelayCDNStateUpdate
     * @desc 添加/删除转推 CDN 地址状态回调。
     *
     * 详情描述:开发者可根据该回调判断转推 CDN 的音视频流是否正常,若不正常根据异常原因进一步定位转推 CDN 的音视频流异常的原因,以及做对应的容灾策略。
     * 通知时机:在 ZEGO RTC 服务器将音视频流转推到 CDN 后,如果 CDN 转推状态发生变化,例如出现转推停止或转推重试,将会收到此回调。
     * 注意事项:若对异常的原因不了解,可联系 ZEGO 技术人员分析具体异常的原因。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 推流的流 ID。
     * @property {ZegoStreamRelayCDNInfo[]} result.infoList - 当前 CDN 正在转推的信息列表。
     */

    /**
     * @event ZegoExpressEngine#onPlayerStateUpdate
     * @desc 拉流状态变更回调。
     *
     * 详情描述:在调用拉流接口 [startPlayingStream] 成功后,可以通过该回调函数获取拉流状态变更的通知。开发者可根据 state 参数是否在 [正在请求拉流状态] 来大体判断用户的拉流网络情况。
     * 通知时机:在调用拉流接口 [startPlayingStream] 成功后,拉流状态变更时。
     * 相关回调:在调用推流接口 [startPublishingStream] 成功后,可以通过回调函数 [onPublisherStateUpdate] 获取推流状态变更的通知。开发者可根据 state 参数是否在 [正在请求推流状态] 来大体判断用户的推流网络情况。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 流 ID。
     * @property {ZegoPlayerState} result.state - 拉流状态。
     * @property {number} result.errorCode - 拉流状态变更对应的错误码。请参考 常见错误码文档 https://doc-zh.zego.im/zh/4378.html。
     * @property {string} result.extendedData - 状态更新附带的扩展信息。备用,目前仅返回空 json 表。
     */

    /**
     * @event ZegoExpressEngine#onPlayerQualityUpdate
     * @desc 拉流质量回调。
     *
     * 详情描述:在调用拉流接口 [startPlayingStream] 成功后每3秒会收到此回调,通过该回调可以获取拉取的音视频流的帧率,码率,RTT,丢包率等质量数据。
     * 业务场景:开发者可根据此函数的质量参数实时监控拉取的音视频流的健康情况,以便在设备 UI 界面上实时展示下行网络状况。
     * 注意事项:若开发者不清楚该回调函数的各个参数应该如何使用,可以只关注其中的 quality 参数的 level 字段,这是 SDK 内部根据质量参数计算的一个描述下行网络的综合值。
     * 相关回调:当调用推流接口 [startPublishingStream] 成功后每3秒会收到回调 [onPublisherQualityUpdate],开发者可根据推送的音视频流的帧率,码率,RTT,丢包率等质量数据,实时监控推送流的健康情况。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     * @property {ZegoPlayStreamQuality} result.quality - 拉流质量,包含了音视频帧率、码率、RTT 等值。
     */

    /**
     * @event ZegoExpressEngine#onPlayerMediaEvent
     * @desc 拉流媒体事件回调。
     *
     * 详情描述:该回调用于接收拉流媒体事件。
     * 业务场景:开发者可以根据此回调对卡顿情况做统计或在 App 的 UI 界面做友好的展示。
     * 通知时机:在调用拉流接口 [startPlayingStream]后,当拉流发生音视频卡顿以及恢复等事件发生时会触发此回调。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     * @property {ZegoPlayerMediaEvent} result.event - 拉流时收到的具体事件。
     */

    /**
     * @event ZegoExpressEngine#onPlayerRecvAudioFirstFrame
     * @desc 拉流端音频接收首帧回调。
     *
     * 详情描述:调用拉流函数 [startPlayingStream] 成功后,SDK 接收到第一帧音频数据时会收到此回调。
     * 业务场景:开发者可用该回调来统计首帧耗时或更新播放流的 UI 组件。
     * 通知时机:SDK 从网络接收到第一帧音频数据时,会收到该回调。
     * 相关回调:调用拉流函数 [startPlayingStream] 成功后, 通过回调函数 [onPlayerRecvVideoFirstFrame] 判断 SDK 是否接收到视频数据,通过回调 [onPlayerRenderVideoFirstFrame] 判断 SDK 是否渲染完接收到的第一帧视频数据。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     */

    /**
     * @event ZegoExpressEngine#onPlayerRecvVideoFirstFrame
     * @desc 拉流端视频接收首帧回调。
     *
     * 详情描述:调用拉流函数 [startPlayingStream] 成功后,SDK 接收到第一帧视频数据时会收到此回调。
     * 业务场景:开发者可用该回调来统计首帧耗时或更新播放流的 UI 组件。
     * 通知时机:SDK 从网络接收到第一帧视频数据时,会收到该回调。
     * 相关回调:调用拉流函数 [startPlayingStream] 成功后, 通过回调函数 [onPlayerRecvAudioFirstFrame] 判断 SDK 是否接收到音频数据,通过回调 [onPlayerRenderVideoFirstFrame] 判断 SDK 是否渲染完接收到的第一帧视频数据。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     */

    /**
     * @event ZegoExpressEngine#onPlayerRenderVideoFirstFrame
     * @desc 拉流端渲染完视频首帧回调。
     *
     * 详情描述:调用拉流函数 [startPlayingStream] 成功后,SDK 拉流并渲染完第一帧视频数据后会收到此回调。
     * 业务场景:开发者可用该回调来统计首帧耗时或更新播放流的 UI 组件。
     * 通知时机:SDK 拉流并渲染完第一帧视频数据后会收到此回调。
     * 相关回调:调用拉流函数 [startPlayingStream] 成功后, 通过回调函数 [onPlayerRecvAudioFirstFrame] 判断 SDK 是否接收到音频数据,通过回调 [onPlayerRecvVideoFirstFrame] 判断 SDK 是否接收到第一帧视频数据。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     */

    /**
     * @event ZegoExpressEngine#onPlayerVideoSizeChanged
     * @desc 拉流分辨率变更通知。
     *
     * 详情描述:调用拉流函数 [startPlayingStream] 成功后,当收到视频首帧数据,或推流方通过 [setVideoConfig] 改变编码分辨率,或流控策略生效时,拉流分辨率会发生改变。
     * 业务场景:开发者可根据流的最终分辨率来更新或切换真正播放流的 UI 组件。
     * 通知时机:拉流 [startPlayingStream] 成功后,在拉流中途如果有视频分辨率发生变化将会收到此回调。
     * 注意事项:若拉的是流只有音频数据,则不会收到该回调。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     * @property {number} result.width - 视频解码分辨率宽。
     * @property {number} result.height - 视频解码分辨率高。
     */

    /**
     * @event ZegoExpressEngine#onPlayerRecvSEI
     * @desc 收到远端流的 SEI 内容。
     *
     * 详情描述:调用拉流函数 [startPlayingStream] 成功后,当远端流发送 SEI 后(如 直接调用 [sendSEI] 、混音中带 SEI 数据、自定义视频采集发送码流数据时附带 SEI 等等),本端会收到此回调。
     * 通知时机:拉流 [startPlayingStream] 成功后,当远端流发送 SEI 后,本端会收到此回调。
     * 注意事项:由于视频编码器自身会产生 payload type 为 5 的 SEI,或者使用视频文件推流时,视频文件中也可能存在这样的 SEI,因此若开发者需要过滤掉这类型的 SEI 时,可在 [createEngine] 之前调用 [ZegoEngineConfig.advancedConfig("unregister_sei_filter", "XXXXX")]。其中 unregister_sei_filter 为 key,XXXXX 为需要设置的uuid过滤字符串。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     * @property {UInt8Array} result.data - SEI 内容。
     */

    /**
     * @event ZegoExpressEngine#onAudioDeviceStateChanged
     * @desc 音频设备状态改变
     *
     * 监测到系统中有音频设备添加或移除时,会触发此回调。通过监听此回调,用户可在必要的时候更新使用特定设备进行声音采集或输出。
     * @property {object} result - 结果数据对象
     * @property {ZegoUpdateType} result.updateType - 更新类型(添加/删除)
     * @property {ZegoAudioDeviceType} result.deviceType - 音频设备类型
     * @property {ZegoDeviceInfo} result.deviceInfo - 音频设备信息
     */

    /**
     * @event ZegoExpressEngine#onVideoDeviceStateChanged
     * @desc 视频设备状态改变。
     *
     * 详情描述:通过监听此回调,用户可在必要的时候更新使用特定设备进行视频采集。
     * 通知时机:监测到系统中有视频设备添加或移除时,会触发此回调。
     * 使用限制:无。
     * @property {object} result - 结果数据对象
     * @property {ZegoUpdateType} result.updateType - 更新类型(添加/删除)
     * @property {ZegoDeviceInfo} result.deviceInfo - 视频设备信息
     */

    /**
     * @event ZegoExpressEngine#onCapturedSoundLevelUpdate
     * @desc 本地采集音频声浪回调。
     *
     * 详情描述:本地采集音频声浪回调。
     * 通知时机:调用 [startSoundLevelMonitor] 函数启动声浪监控器后。
     * 注意事项:回调通知周期为调用 [startSoundLevelMonitor] 时设置的参数值,当处于未推流 [startPublishingStream] 或未预览 [startPreview] 状态时,回调数值为默认值 0。
     * 相关接口:通过 [startSoundLevelMonitor] 启动声浪监控,通过回调 [onRemoteSoundLevelUpdate] 监控远端拉流音频声浪。
     * @property {object} result - 结果数据对象
     * @property {number} result.soundLevel - 本地采集的声浪值,取值范围为 0.0 ~ 100.0。
     */

    /**
     * @event ZegoExpressEngine#onRemoteSoundLevelUpdate
     * @desc 远端拉流音频声浪回调。
     *
     * 详情描述:远端拉流音频声浪回调。
     * 通知时机:调用 [startSoundLevelMonitor] 函数启动声浪监控器后,且处于正在拉流 [startPlayingStream] 的状态。
     * 注意事项:回调通知周期为调用 [startSoundLevelMonitor] 时设置的参数值。
     * 相关接口:通过 [startSoundLevelMonitor] 启动声浪监控,通过回调 [onCapturedSoundLevelUpdate] 或 [onCapturedSoundLevelInfoUpdate] 监控本地拉流音频声浪。
     * @property {object} result - 结果数据对象
     * @property {Object} result.soundLevels - 远端的声浪键值对,key 为流 ID,value 为对应的流的声浪值,value 取值范围为 0.0 ~ 100.0。
     */

    /**
     * @event ZegoExpressEngine#onCapturedAudioSpectrumUpdate
     * @desc 本地采集音频频谱回调。
     *
     * 详情描述:本地采集音频频谱回调。
     * 通知时机:调用 [startAudioSpectrumMonitor] 函数启动声浪监控器后。
     * 注意事项:回调通知周期为调用 [startAudioSpectrumMonitor] 时设置的参数值,当处于未推流 [startPublishingStream] 或未预览 [startPreview] 状态时,回调数值为默认值 0。
     * 相关接口:通过 [startAudioSpectrumMonitor] 启动声浪监控,通过回调 [onRemoteSoundLevelUpdate] 监控远端拉流音频频谱。
     * @property {object} result - 结果数据对象
     * @property {number[]} result.audioSpectrum - 本地采集的音频频谱值数组,频谱值范围为 [0-2^30]。
     */

    /**
     * @event ZegoExpressEngine#onRemoteAudioSpectrumUpdate
     * @desc 远端拉流音频频谱回调。
     *
     * 详情描述:远端拉流音频频谱回调。
     * 通知时机:调用 [startAudioSpectrumMonitor] 函数启动声浪监控器后,且处于正在拉流 [startPlayingStream] 的状态。
     * 注意事项:回调通知周期为调用 [startAudioSpectrumMonitor] 时设置的参数值。
     * 相关接口:通过 [startAudioSpectrumMonitor] 启动音频频谱监控,通过回调 [onCapturedAudioSpectrumUpdate] 监控本地采集音频频谱。
     * @property {object} result - 结果数据对象
     * @property {object} result.audioSpectrums - 远端音频频谱键值对,key 是流 ID,value 为对应的流的音频频谱值数组,频谱值范围为 [0-2^30]
     */

    /**
     * @event ZegoExpressEngine#onDeviceError
     * @desc 设备异常通知。
     *
     * 详情描述:设备异常通知。
     * 通知时机:当本地音频或视频设备读写出现异常时会触发此回调。
     * @property {object} result - 结果数据对象
     * @property {number} result.errorCode - 设备异常的错误码。请参考 常见错误码文档 https://doc-zh.zego.im/zh/4378.html
     * @property {string} result.deviceName - 设备名称
     */

    /**
     * @event ZegoExpressEngine#onRemoteCameraStateUpdate
     * @desc 远端摄像头设备状态通知。
     *
     * 详情描述:远端摄像头设备状态通知。
     * 业务场景:1v1 教育场景的开发者或者教育小班课场景及相似场景的开发者可以根据此回调来判断远端推流设备的摄像头设备是否正常工作,以及根据相应的 state 初步了解设备出问题的原因。
     * 通知时机:远端摄像头设备状态发生变更时,例如开关摄像头等,通过监听此回调,能够获取远端摄像头相关的事件,可以用于提示用户可能导致视频异常的情况。
     * 注意事项:当从 CDN 拉流时,或对端使用了自定义视频采集时,不会触发此回调。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     * @property {ZegoRemoteDeviceState} result.state - 远端摄像头状态。
     */

    /**
     * @event ZegoExpressEngine#onRemoteMicStateUpdate
     * @desc 远端麦克风设备状态通知。
     *
     * 详情描述:远端麦克风设备状态通知。
     * 业务场景:1v1 教育场景的开发者或者教育小班课场景及相似场景的开发者可以根据此回调来判断远端推流设备的麦克风设备是否正常工作,以及根据相应的 state 初步了解设备出问题的原因。
     * 通知时机:远端麦克风设备状态发生变更时,例如开关麦克风等,通过监听此回调,能够获取远端麦克风相关的事件,可以用于提示用户可能导致音频异常的情况。
     * 注意事项:当从 CDN 拉流时,或对端使用了自定义音频采集时(且不是推流到 ZEGO RTC服务器),不会触发此回调。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     * @property {ZegoRemoteDeviceState} result.state - 远端麦克风状态。
     */

    /**
     * @event ZegoExpressEngine#onRemoteSpeakerStateUpdate
     * @desc 远端扬声器设备状态通知。
     *
     * 详情描述:远端扬声器设备状态通知。
     * 业务场景:1v1 教育场景的开发者或者教育小班课场景及相似场景的开发者可以根据此回调来判断远端推流设备的扬声器设备是否正常工作,以及根据相应的 state 初步了解设备出问题的原因。
     * 通知时机:远端扬声器设备状态发生变更时,例如开关扬声器等,通过监听此回调,能够获取远端扬声器相关的事件。
     * 注意事项:此回调当从 CDN 拉流时不会回调。
     * @property {object} result - 结果数据对象
     * @property {string} result.streamID - 拉流的流 ID。
     * @property {ZegoRemoteDeviceState} result.state - 远端扬声器状态。
     */

    /**
     * @event ZegoExpressEngine#onIMRecvBroadcastMessage
     * @desc 接收房间广播消息通知。
     *
     * 详情描述:该回调用于接收相同房间内其他用户发送的广播消息。
     * 业务场景:一般在直播房间人数不超过 500 时使用。
     * 通知时机:调用 [loginRoom] 登录房间之后,如果房间内有用户通过 [sendBroadcastMessage] 函数发送广播消息,则触发此回调。
     * 使用限制:无。
     * 注意事项:用户自己发送的广播消息不会通过此回调得到通知。
     * 相关回调:可通过[onIMRecvBarrageMessage]接收房间弹幕消息,可通过 [onIMRecvCustomCommand] 接收房间自定义信令。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 房间 ID。取值范围:最大长度为 128 字节。注意事项:房间 ID 为字符串格式,仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'。
     * @property {ZegoBroadcastMessageInfo[]} result.messageList - 收到的消息列表。取值范围:每次最多接收 50 条消息。
     */

    /**
     * @event ZegoExpressEngine#onIMRecvBarrageMessage
     * @desc 接收房间弹幕消息通知。
     *
     * 详情描述:该回调用于接收相同房间内其他用户发送的弹幕消息。
     * 业务场景:一般用于房间内有大量消息收发,且不需要保证消息可靠性的场景,例如直播弹幕。
     * 通知时机:调用 [loginRoom] 登录房间之后,如果房间内有用户通过 [sendBarrageMessage] 函数发送弹幕消息,则触发此回调。
     * 使用限制:无。
     * 注意事项:用户自己发送的弹幕消息不会通过此回调得到通知。在房间内有大量弹幕消息时可能会延迟收到通知,且可能丢失部分弹幕消息。
     * 相关回调:可通过[onIMRecvBroadcastMessage]接收房间广播消息,可通过 [onIMRecvCustomCommand] 接收房间自定义信令。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 房间 ID。取值范围:最大长度为 128 字节。注意事项:房间 ID 为字符串格式,仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'。
     * @property {ZegoBarrageMessageInfo[]} result.messageList - 收到的消息列表。取值范围:每次最多接收 50 条消息。
     */

    /**
     * @event ZegoExpressEngine#onIMRecvCustomCommand
     * @desc 接收自定义信令通知。
     *
     * 详情描述:该回调用于接收相同房间内其他用户发送的自定义信令。
     * 业务场景:一般在直播房间人数不超过 500 时使用。
     * 通知时机:调用 [loginRoom] 登录房间之后,如果房间内有其他用户通过 [sendCustomCommand] 函数发送自定义信令给开发者,则触发此回调。
     * 使用限制:无。
     * 注意事项:用户自己发送给自己的自定义信令不会通过此回调得到通知。
     * 相关回调:可通过[onIMRecvBroadcastMessage]接收房间广播消息,可通过 [onIMRecvBarrageMessage] 接收房间弹幕消息。
     * @property {object} result - 结果数据对象
     * @property {string} result.roomID - 房间 ID。取值范围:最大长度为 128 字节。注意事项:房间 ID 为字符串格式,仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'。
     * @property {ZegoUser} result.fromUser - 信令的发送人。
     * @property {string} result.command - 信令内容。取值范围:最大长度为 1024 字节。
     */

    /**
     * @event ZegoExpressEngine#onCapturedDataRecordStateUpdate
     * @desc 本地录制的状态更新回调,当录制过程状态变化时触发。
     *
     * 详情描述:本地录制的状态更新回调,当录制过程状态变化时触发。
     * 业务场景:开发者应根据此回调来判断文件录制的状态或者进行 UI 的提示等。
     * 通知时机:调用 [startRecordingCapturedData] 后,当录制过程状态变化时触发。
     * 使用限制:无。
     * @property {object} result - 结果数据对象
     * @property {ZegoDataRecordState} result.state - 文件录制状态。
     * @property {number} result.errorCode - 错误码,详情请参考 常见错误码文档 https://doc-zh.zego.im/zh/4378.html
     * @property {ZegoDataRecordConfig} result.config - 录制配置对象。
     * @property {ZegoPublishChannel} result.channel - 推流通道。
     */

    /**
     * @event ZegoExpressEngine#onCapturedDataRecordProgressUpdate
     * @desc 录制进度更新回调。
     *
     * 详情描述:本地录制的进度更新回调,录制过程中定时触发。
     * 业务场景:开发者可以此对用户界面进行 UI 的提示等。
     * 通知时机:调用 [startRecordingCapturedData] 后,如果配置了需要回调,录制过程中定时触发。
     * 使用限制:无。
     * @property {object} result - 结果数据对象
     * @property {ZegoDataRecordProgress} result.progress - 文件录制过程进度,开发者可以此对用户界面进行 UI 的提示等。
     * @property {ZegoDataRecordConfig} result.config - 录制配置对象。
     * @property {ZegoPublishChannel} result.channel - 推流通道。
     */

    /**
     * @event ZegoExpressEngine#onNetworkModeChanged
     * @desc 网络模式变更回调。
     *
     * 详情描述:网络模式变更回调。
     * 通知时机:当设备的网络模式改变时,例如从 WiFi 切换到 5G,或断网等情况,将会触发本回调。
     * 使用限制:无。
     * @property {object} result - 结果数据对象
     * @property {ZegoNetworkMode} result.mode - 当前网络模式。
     */

    /**
     * @event ZegoExpressEngine#onNetworkSpeedTestError
     * @desc 网络测速异常回调。
     *
     * 详情描述:网络测速异常回调。
     * 业务场景:用于检测当前网络环境是否适合推/拉指定码率的流。
     * 通知时机:网络测试过程中发生异常时,例如:连接测速服务器失败等,将触发本回调。
     * 使用限制:无。
     * @property {object} result - 结果数据对象
     * @property {number} result.errorCode - 网络测速错误码。请参考常见错误码文档 https://doc-zh.zego.im/zh/4378.html。
     * @property {ZegoNetworkSpeedTestType} result.type - 上行或下行网络。
     */

    /**
     * @event ZegoExpressEngine#onNetworkSpeedTestQualityUpdate
     * @desc 网络测速质量回调。
     *
     * 详情描述:网络测速质量回调。
     * 业务场景:用于检测当前网络环境是否适合推/拉指定码率的流。
     * 通知时机:调用 [startNetworkSpeedTest] 启动网络测速后,将触发本回调。回调通知周期为调用 [startNetworkSpeedTest] 时设置的参数值,未设置该参数时,默认 3 秒回调一次。
     * 使用限制:无。
     * 注意事项:当测速发生异常或停止测速时,本回调将会不再触发。
     * @property {object} result - 结果数据对象
     * @property {ZegoNetworkSpeedTestQuality} result.quality - 网速测速质量.
     * @property {ZegoNetworkSpeedTestType} result.type - 上行或下行网络。
    /**
     * @event ZegoExpressEngine#onRecvExperimentalAPI
     * @desc 接收自定义 JSON 内容 
     *
     * @property {object} result - 结果数据对象
     * @property {string} result.content - JSON 字符串内容
     */


    callEmit() {
        try {
            if (arguments[0] === "onCapturedVideoFrameRawData") {
                let channel = arguments[1]["channel"];
                let videoFrame = {
                    "channel": channel,
                    "videoFrameParam": arguments[1]["videoFrameParam"],
                    "videoFrameBuffer": Buffer.from(arguments[1]["videoFrameBuffer"])
                }
                this.VideoViewManager.localGLRenders[channel].drawVideoFrame(videoFrame);
            }
            else if (arguments[0] === "onRemoteVideoFrameRawData") {
                let streamID = arguments[1]["streamID"];
                let videoFrame = {
                    "streamID": streamID,
                    "videoFrameParam": arguments[1]["videoFrameParam"],
                    "videoFrameBuffer": Buffer.from(arguments[1]["videoFrameBuffer"])
                }
                this.VideoViewManager.remoteGLRenders[streamID].drawVideoFrame(videoFrame);
            }
            else if (arguments[0] === "onDebugInfo") {
                if (this.isConsolePrintDebugInfo) {
                    console.info(arguments[1]["info"]);
                }
            }
            else if (arguments[0] === "onDebugError") {
                if (this.isConsolePrintDebugInfo) {
                    console.error(`onDebugError: funcName=${arguments[1]["funcName"]} ErrorCode=${arguments[1]["errorCode"]} ErrorInfo=${arguments[1]["errorInfo"]}`)
                    // dialog.showErrorBox(arguments[1]["alertTitle"], arguments[1]["alertBody"]);
                }
            }
            else if(arguments[0].startsWith("MEDIAPLAYER_")){
                let mediaPlayer = this.mediaPlayers[arguments[1]["nativeMediaPlayerPtr"]];
                if(mediaPlayer){
                    mediaPlayer.callEmit(arguments[0].replace("MEDIAPLAYER_", ""), arguments[1])
                }
            }
            else {
                const highFrequencyCallbacks = ["onPublisherQualityUpdate",
                "onPlayerQualityUpdate", "onMixerSoundLevelUpdate",
                "onCapturedSoundLevelUpdate", "onRemoteSoundLevelUpdate",
                "onCapturedAudioSpectrumUpdate", "onRemoteAudioSpectrumUpdate",
                "MEDIAPLAYER_onMediaPlayerPlayingProgress", "onRoomOnlineUserCountUpdate"];
                if(!highFrequencyCallbacks.includes(arguments[0]) && this.isConsolePrintDebugInfo){
                    console.log(arguments[0], arguments[1]);
                }
            }
        } catch (error) {
            // console.log("callEmit: ", error);
        }
        try {
            this.emit(arguments[0], arguments[1]);
        } catch (error) {
            console.log(`error catched in your callback ${arguments[0]} : ${error}`)
        }
    }
}

const ZegoExpressEngineInstance = new ZegoExpressEngine;
module.exports = ZegoExpressEngineInstance;