import AVFoundation
import TXLiteAVSDK_Professional

@objc(TRTCReactNativeSdk)
class TRTCReactNativeSdk: RCTEventEmitter, TRTCCloudDelegate {
    
    private var hasListeners = false
    private var txCloudManager: TRTCCloud!;
    private var txAudioEffectManager: TXAudioEffectManager!;
    private var txDeviceManager:TXDeviceManager!;
    private var txBeautyManager:TXBeautyManager!;
    
    override func supportedEvents() -> [String]! {
        return ["onListener"]
    }
    
    // sdk manager begin
    @objc(sharedInstance:withRejecter:)
    func sharedInstance(resolve: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager = TRTCCloud.sharedInstance();
        txAudioEffectManager = TRTCCloud.sharedInstance().getAudioEffectManager();
        txDeviceManager = TRTCCloud.sharedInstance().getDeviceManager();
        txBeautyManager = TRTCCloud.sharedInstance().getBeautyManager();
        txCloudManager.delegate = self;
        resolve(0);
    }
    
    @objc(getSDKVersion:withRejecter:)
    func getSDKVersion(resolve: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        resolve(TRTCCloud.getSDKVersion());
    }

    @objc(stopLocalPreview:withRejecter:)
    func stopLocalPreview(resolve: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.stopLocalPreview();
        resolve(0);
    }
    
    @objc(enterRoom:withScene:withResolver:withRejecter:)
    func enterRoom(param: NSDictionary, scene: Int, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let sdkAppId = param["sdkAppId"] as? UInt32,
           let userId = param["userId"] as? String,
           let userSig = param["userSig"] as? String,
           let roomId = param["roomId"] as? UInt32,
           let strRoomId = param["strRoomId"] as? String,
           let role = param["role"] as? Int,
           let streamId = param["streamId"] as? String,
           let userDefineRecordId = param["userDefineRecordId"] as? String,
           let privateMapKey = param["privateMapKey"] as? String,
           let businessInfo = param["businessInfo"] as? String {
            let params = TRTCParams();
            params.sdkAppId = sdkAppId;
            params.userId = userId;
            params.userSig = userSig;
            params.roomId = roomId;
            params.strRoomId = strRoomId;
            params.streamId = streamId;
            params.userDefineRecordId = userDefineRecordId;
            params.privateMapKey = privateMapKey;
            params.bussInfo = businessInfo;
            params.role = TRTCRoleType(rawValue: role)!;
            
            txCloudManager.callExperimentalAPI("{\"api\": \"setFramework\", \"params\": {\"framework\": 22}}");
            txCloudManager.enterRoom(params, appScene: TRTCAppScene(rawValue: scene)!);
            result(0);
        } else {
            result(-1);
        }
    }
    
    @objc(exitRoom:withRejecter:)
    func exitRoom(resolve: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.exitRoom();
        resolve(0);
    }

  @objc(getAudioEffectManager:withRejecter:)
    func getAudioEffectManager(resolve: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.getAudioEffectManager();
        resolve(0);
    }

  @objc(getDeviceManager:withRejecter:)
    func getDeviceManager(resolve: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.getDeviceManager();
        resolve(0);
    }
    
    @objc(getBeautyManager:withRejecter:)
    func getBeautyManager(resolve: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.getBeautyManager();
        resolve(0);
    }
    
  @objc(connectOtherRoom:withResolver:withRejecter:)
    func connectOtherRoom(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let param = param["param"] as? String {
            txCloudManager.connectOtherRoom(param);
            result(nil);
        }
    }
    
  @objc(disconnectOtherRoom:withRejecter:)
    func disconnectOtherRoom(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.disconnectOtherRoom();
        result(nil);
    }
    
  @objc(switchRoom:withResolver:withRejecter:)
    func switchRoom(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        let config = JsonUtil.getDictionaryFromJSONString(jsonString: (param["config"] as? String)!);
        
        if let userSig = config["userSig"] as? String,
           let roomId = config["roomId"] as? UInt32,
           let strRoomId = config["strRoomId"] as? String,
           let privateMapKey = config["privateMapKey"] as? String {
            let params = TRTCSwitchRoomConfig();
            params.userSig = userSig;
            params.roomId = roomId;
            params.strRoomId = strRoomId;
            params.privateMapKey = privateMapKey;
            
            txCloudManager.switchRoom(params);
            result(nil);
        }
    }
    
  @objc(switchRole:withResolver:withRejecter:)
    func switchRole(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let role = param["role"] as? Int {
            txCloudManager.switch(TRTCRoleType(rawValue: role)!);
            result(nil);
        }
    }
    
  // @objc(setDefaultStreamRecvMode:withResolver:withRejecter:)
    // func setDefaultStreamRecvMode(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
    //     if let autoRecvAudio = param["autoRecvAudio"] as? Bool,
    //        let autoRecvVideo = param["autoRecvVideo"] as? Bool {
    //         txCloudManager.setDefaultStreamRecvMode(autoRecvAudio, video: autoRecvVideo);
    //         result(nil);
    //     }
    // }

  @objc(muteRemoteAudio:withResolver:withRejecter:)
    func muteRemoteAudio(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let userId = param["userId"] as? String,
           let mute = param["mute"] as? Bool {
            txCloudManager.muteRemoteAudio(userId, mute: mute);
            result(nil);
        }
    }

  @objc(muteAllRemoteAudio:withResolver:withRejecter:)
    func muteAllRemoteAudio(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let mute = param["mute"] as? Bool {
            txCloudManager.muteAllRemoteAudio(mute);
            result(nil);
        }
    }
    
  @objc(setAudioCaptureVolume:withResolver:withRejecter:)
    func setAudioCaptureVolume(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let volume = param["volume"] as? Int {
            txCloudManager.setAudioCaptureVolume(volume);
            result(nil);
        }
    }

  @objc(setRemoteAudioVolume:withResolver:withRejecter:)
    func setRemoteAudioVolume(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let userId = param["userId"] as? String,
           let volume = param["volume"] as? Int32 {
            txCloudManager.setRemoteAudioVolume(userId, volume: volume);
            result(nil);
        }
    }

  @objc(setAudioPlayoutVolume:withResolver:withRejecter:)
    func setAudioPlayoutVolume(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let volume = param["volume"] as? Int {
            txCloudManager.setAudioPlayoutVolume(volume);
            result(nil);
        }
    }
    
  @objc(getAudioCaptureVolume:withRejecter:)
    func getAudioCaptureVolume(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        let volume = txCloudManager.getAudioCaptureVolume();
        result(volume);
    }

  @objc(getAudioPlayoutVolume:withRejecter:)
    func getAudioPlayoutVolume(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        let volume = txCloudManager.getAudioPlayoutVolume();
        result(volume);
    }
    
  @objc(startLocalAudio:withResolver:withRejecter:)
    func startLocalAudio(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let quality = param["quality"] as? Int {
            txCloudManager.startLocalAudio(TRTCAudioQuality(rawValue: quality)!);
            result(nil);
        }
    }

  @objc(stopLocalAudio:withRejecter:)
    func stopLocalAudio(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.stopLocalAudio();
        result(nil);
    }

  @objc(setLocalRenderParams:withResolver:withRejecter:)
    func setLocalRenderParams(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let param = param["param"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: param);
            let data = TRTCRenderParams();
            if dict["rotation"] != nil {
                data.rotation = TRTCVideoRotation(rawValue: dict["rotation"] as! Int)!;
            }
            if dict["fillMode"] != nil {
                data.fillMode = TRTCVideoFillMode(rawValue: dict["fillMode"] as! Int)!;
            }
            if dict["mirrorType"] != nil {
                data.mirrorType = TRTCVideoMirrorType(rawValue: dict["mirrorType"] as! UInt)!;
            }
            txCloudManager.setLocalRenderParams(data);
            result(nil);
        }
    }

  @objc(setRemoteRenderParams:withResolver:withRejecter:)
    func setRemoteRenderParams(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let userId = param["userId"] as? String,
           let streamType = param["streamType"] as? Int,
           let param = param["param"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: param);
            let data = TRTCRenderParams();
            if dict["rotation"] != nil {
                data.rotation = TRTCVideoRotation(rawValue: dict["rotation"] as! Int)!;
            }
            if dict["fillMode"] != nil {
                data.fillMode = TRTCVideoFillMode(rawValue: dict["fillMode"] as! Int)!;
            }
            if dict["mirrorType"] != nil {
                data.mirrorType = TRTCVideoMirrorType(rawValue: dict["mirrorType"] as! UInt)!;
            }
            txCloudManager.setRemoteRenderParams(userId, streamType: TRTCVideoStreamType(rawValue: streamType)!,  params: data);
            result(nil);
        }
    }
    
  @objc(stopAllRemoteView:withResolver:withRejecter:)
    func stopAllRemoteView(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.stopAllRemoteView();
        result(nil);
    }

  @objc(muteRemoteVideoStream:withResolver:withRejecter:)
    func muteRemoteVideoStream(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let userId = param["userId"] as? String,
           let mute = param["mute"] as? Bool {
            txCloudManager.muteRemoteVideoStream(userId, mute: mute);
            result(nil);
        }
    }

  @objc(muteAllRemoteVideoStreams:withResolver:withRejecter:)
    func muteAllRemoteVideoStreams(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let mute = param["mute"] as? Bool {
            txCloudManager.muteAllRemoteVideoStreams(mute);
            result(nil);
        }
    }

  @objc(setVideoEncoderParam:withResolver:withRejecter:)
    func setVideoEncoderParam(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let param = param["param"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: param);
            let data = TRTCVideoEncParam();
            if dict["videoBitrate"] != nil {
                data.videoBitrate = dict["videoBitrate"] as! Int32;
            }
            if dict["videoResolution"] != nil {
                data.videoResolution = TRTCVideoResolution(rawValue: dict["videoResolution"] as! Int)!;
            }
            if dict["videoResolutionMode"] != nil {
                data.resMode = TRTCVideoResolutionMode(rawValue: dict["videoResolutionMode"] as! Int)!;
            }
            if dict["videoFps"] != nil {
                data.videoFps = dict["videoFps"] as! Int32;
            }
            txCloudManager.setVideoEncoderParam(data);
            result(nil);
        }
    }

  @objc(startPublishing:withResolver:withRejecter:)
    func startPublishing(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let streamType = param["streamType"] as? Int,
           let streamId = param["streamId"] as? String {
            txCloudManager.startPublishing(streamId, type: TRTCVideoStreamType(rawValue: streamType)!);
            result(nil);
            
        }
    }

    @objc(stopRemoteView:withResolver:withRejecter:)
    func stopRemoteView(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let streamType = param["streamType"] as? Int,
            let userId = param["userId"] as? String {
            txCloudManager.stopRemoteView(userId, streamType: TRTCVideoStreamType(rawValue: streamType)!);
            result(nil);
            
        }
    }
    
  @objc(startPublishCDNStream:withResolver:withRejecter:)
    func startPublishCDNStream(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        let param = param["param"] as! String;
        let dict = JsonUtil.getDictionaryFromJSONString(jsonString: param);
        
        if let appId = dict["appId"] as? Int32,
           let bizId = dict["bizId"] as? Int32,
           let url = dict["url"] as? String {
            let params = TRTCPublishCDNParam();
            params.appId = appId;
            params.bizId = bizId;
            params.url = url;
            
            txCloudManager.startPublishCDNStream(params);
            result(nil);
        }
    }

  @objc(stopPublishCDNStream:withRejecter:)
    func stopPublishCDNStream(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.stopPublishCDNStream();
        result(nil);
    }
    
  @objc(stopPublishing:withRejecter:)
    func stopPublishing(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.stopPublishing();
        result(nil);
    }

  @objc(setMixTranscodingConfig:withResolver:withRejecter:)
    func setMixTranscodingConfig(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let param = param["config"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: param);
            let backgroundImage = dict["backgroundImage"] as? String;
            let streamId = dict["streamId"] as? String;
            
            if let appId = dict["appId"] as? Int32,
               let bizId = dict["bizId"] as? Int32,
               let videoWidth = dict["videoWidth"] as? Int32,
               let mode = dict["mode"] as? Int,
               let videoHeight = dict["videoHeight"] as? Int32,
               let videoFramerate = dict["videoFramerate"] as? Int32,
               let videoGOP = dict["videoGOP"] as? Int32,
               let backgroundColor = dict["backgroundColor"] as? Int32,
               let videoBitrate = dict["videoBitrate"] as? Int32,
               let audioBitrate = dict["audioBitrate"] as? Int32,
               let audioSampleRate = dict["audioSampleRate"] as? Int32,
               let audioChannels = dict["audioChannels"] as? Int32,
               let mixUsers = dict["mixUsers"] as? Array<AnyObject> {
                
                let config = TRTCTranscodingConfig();
                var users: [TRTCMixUser] = [];
                
                config.appId = appId;
                config.bizId = bizId;
                config.videoWidth = videoWidth;
                config.mode = TRTCTranscodingConfigMode(rawValue: mode)!;
                config.videoHeight = videoHeight;
                config.videoFramerate = videoFramerate;
                config.videoGOP = videoGOP;
                config.backgroundImage = backgroundImage;
                config.backgroundColor = backgroundColor;
                config.videoBitrate = videoBitrate;
                config.audioBitrate = audioBitrate;
                config.audioSampleRate = audioSampleRate;
                config.audioChannels = audioChannels;
                config.streamId = streamId;
                
                for item in mixUsers {
                    let user = TRTCMixUser();
                    user.userId = item["userId"] as! String;
                    user.roomID = item["roomId"] as? String;
                    user.rect = CGRect(x: item["x"] as! Int, y: item["y"] as! Int, width: item["width"] as! Int, height: item["height"] as! Int);
                    user.zOrder = item["zOrder"] as! Int32;
                    user.streamType = TRTCVideoStreamType(rawValue: item["streamType"] as! Int)!;
                    user.pureAudio = (item["pureAudio"] as? Bool) ?? false;
                    users.append(user);
                }
                
                config.mixUsers = users;
                txCloudManager.setMix(config);
                
                result(nil);
            }
        }
    }
    
  @objc(setNetworkQosParam:withResolver:withRejecter:)
    func setNetworkQosParam(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let param = param["param"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: param);
            let param = TRTCNetworkQosParam();
            
            if !(dict["preference"] is NSNull) &&  dict["preference"] != nil {
                param.preference = TRTCVideoQosPreference(rawValue: dict["preference"] as! Int)!;
            }
            if !(dict["controlMode"] is NSNull) &&  dict["controlMode"] != nil {
                param.controlMode = TRTCQosControlMode(rawValue: dict["controlMode"] as! Int)!;
            }
            
            txCloudManager.setNetworkQosParam(param);
            result(nil);
        }
    }
    
  @objc(setVideoMuteImage:withResolver:withRejecter:)
    func setVideoMuteImage(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        let imageUrl = param["imageUrl"] as? String;
        if     let fps = param["fps"] as? Int,
               let type = param["type"] as? String {
            if(imageUrl == nil) {
                //txCloudManager.setVideoMuteImage(nil, fps: fps);
            } else {
                if type == "local" {} else {
                    let queue = DispatchQueue(label: "setVideoMuteImage")
                    queue.async {
                        let url: NSURL = NSURL(string: imageUrl!)!
                        let data: NSData = NSData(contentsOf: url as URL)!
                        let img = UIImage(data: data as Data, scale: 1)!
                        self.txCloudManager.setVideoMuteImage(img, fps: fps);
                    }
                }
            }
            result(nil);
        }
    }
    
  @objc(setVideoEncoderRotation:withResolver:withRejecter:)
    func setVideoEncoderRotation(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let rotation = param["rotation"] as? Int {
            txCloudManager.setVideoEncoderRotation(TRTCVideoRotation(rawValue: rotation)!);
            result(nil);
        }
    }
    
  @objc(setVideoEncoderMirror:withResolver:withRejecter:)
    func setVideoEncoderMirror(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let mirror = param["mirror"] as? Bool {
            txCloudManager.setVideoEncoderMirror(mirror);
            result(nil);
        }
    }

  @objc(setGSensorMode:withResolver:withRejecter:)
    func setGSensorMode(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let mode = param["mode"] as? Int {
            txCloudManager.setGSensorMode(TRTCGSensorMode(rawValue: mode)!);
            result(nil);
        }
    }
    
  @objc(enableEncSmallVideoStream:withResolver:withRejecter:)
    func enableEncSmallVideoStream(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let enable = param["enable"] as? Bool,
           let smallVideoEncParam = param["smallVideoEncParam"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: smallVideoEncParam);
            let data = TRTCVideoEncParam();
            if !(dict["videoBitrate"] is NSNull) &&  dict["videoBitrate"] != nil {
                data.videoBitrate = dict["videoBitrate"] as! Int32;
            }
            if !(dict["videoResolution"] is NSNull)  &&  dict["videoResolution"] != nil  {
                data.videoResolution = TRTCVideoResolution(rawValue: dict["videoResolution"] as! Int)!;
            }
            if !(dict["videoResolutionMode"] is NSNull)  &&  dict["videoResolutionMode"] != nil  {
                data.resMode = TRTCVideoResolutionMode(rawValue: dict["videoResolutionMode"] as! Int)!;
            }
            if !(dict["videoFps"] is NSNull)  &&  dict["videoFps"] != nil  {
                data.videoFps = dict["videoFps"] as! Int32;
            }
            
            let ret = txCloudManager.enableEncSmallVideoStream(enable, withQuality: data);
            result(ret);
        }
    }
    
  @objc(setRemoteVideoStreamType:withResolver:withRejecter:)
    func setRemoteVideoStreamType(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let userId = param["userId"] as? String,
           let streamType = param["streamType"] as? Int {
            txCloudManager.setRemoteVideoStreamType(userId, type: TRTCVideoStreamType(rawValue: streamType)!);
            result(nil);
        }
    }
    
  @objc(snapshotVideo:withResolver:withRejecter:)
    func snapshotVideo(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
//        let userId = param["userId"] as? String;
//        if let streamType = param["streamType"] as? Int,
//           let path = param["path"] as? String {
//
//            txCloudManager.snapshotVideo(userId, type: TRTCVideoStreamType(rawValue: streamType)!, completionBlock: {
//                (image) -> Void in
//
//                let data: Data
//                let url = URL(fileURLWithPath: "path")
//
//                if path.hasSuffix(".png") {
//                    data = (image?.pngData()!
//                } else {
//                    data = (image?.jpegData(compressionQuality: CGFloat(1))!
//                }
//
//                do {
//                    try data.write(to: url)
//                    TencentTRTCCloud.invokeListener(type: ListenerType.onSnapshotComplete, params: ["errCode": 0, "path": path]);
//                } catch {
//                    CommonUtils.logError(call: call, errCode: -1, errMsg: "\(error)")
//                    TencentTRTCCloud.invokeListener(type: ListenerType.onSnapshotComplete, params: ["errCode": -1, "errMsg": "\(error)", "path": nil]);
//                }
//            });
//            result(nil);
//        }
    }

  @objc(muteLocalAudio:withResolver:withRejecter:)
    func muteLocalAudio(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let mute = param["mute"] as? Bool {
            txCloudManager.muteLocalAudio(mute);
            result(nil);
        }
    }

  @objc(muteLocalVideo:withResolver:withRejecter:)
    func muteLocalVideo(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let mute = param["mute"] as? Bool {
            txCloudManager.muteLocalVideo(mute);
            result(nil);
        }
    }

  @objc(enableAudioVolumeEvaluation:withResolver:withRejecter:)
    func enableAudioVolumeEvaluation(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let intervalMs = param["intervalMs"] as? UInt {
            txCloudManager.enableAudioVolumeEvaluation(intervalMs);
            result(nil);
        }
    }

  @objc(startAudioRecording:withResolver:withRejecter:)
    func startAudioRecording(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let param = param["param"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: param);
            let data = TRTCAudioRecordingParams();
            data.filePath = dict["filePath"] as! String;
            result(txCloudManager.startAudioRecording(data));
        }
    }

  @objc(stopAudioRecording:withRejecter:)
    func stopAudioRecording(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.stopAudioRecording();
        result(nil);
    }
    
  @objc(enable3DSpatialAudioEffect:withResolver:withRejecter:)
    func enable3DSpatialAudioEffect(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let enabled = param["enabled"] as? Bool {
            txCloudManager.enable3DSpatialAudioEffect(enabled);
            result(nil);
        }
    }

  @objc(updateSelf3DSpatialPosition:withResolver:withRejecter:)
    func updateSelf3DSpatialPosition(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let positionArr = param["position"] as? [String],
           let axisForwardArr = param["axisForward"] as? [String],
           let axisRightArr = param["axisRight"] as? [String],
           let axisUpArr = param["axisUp"] as? [String] {
            let positionIntArr = positionArr.compactMap { Int32($0) };
            let position = UnsafeMutablePointer<Int32>.init(mutating: positionIntArr);
            let axisForwardFloatArr = axisForwardArr.compactMap { Float($0) };
            let axisForward = UnsafeMutablePointer<Float>.init(mutating: axisForwardFloatArr);
            let axisRightFloatArr = axisRightArr.compactMap { Float($0) };
            let axisRight = UnsafeMutablePointer<Float>.init(mutating: axisRightFloatArr);
            let axisUpFloatArr = axisUpArr.compactMap { Float($0) };
            let axisUp = UnsafeMutablePointer<Float>.init(mutating: axisUpFloatArr);
            txCloudManager.updateSelf3DSpatialPosition(position, axisForward: axisForward, axisRight: axisRight, axisUp: axisUp);
            result(nil);
        }
    }

  @objc(updateRemote3DSpatialPosition:withResolver:withRejecter:)
    func updateRemote3DSpatialPosition(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let userId = param["userId"] as? String,
           let positionArr = param["position"] as? [String] {
            let positionIntArr = positionArr.compactMap { Int32($0) };
            let position = UnsafeMutablePointer<Int32>.init(mutating: positionIntArr);
            txCloudManager.updateRemote3DSpatialPosition(userId, position: position);
            result(nil);
        }
    }

  @objc(set3DSpatialReceivingRange:withResolver:withRejecter:)
    func set3DSpatialReceivingRange(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let userId = param["userId"] as? String,
           let range = param["range"] as? Int {
            txCloudManager.set3DSpatialReceivingRange(userId, range: range);
            result(nil);
        }
    }

  @objc(setWatermark:withResolver:withRejecter:)
    func setWatermark(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let imageUrl = param["imageUrl"] as? String,
           let streamType = param["streamType"] as? Int,
           let x = param["x"] as? String,
           let y = param["y"] as? String,
           let width = param["width"] as? String,
           let type = param["type"] as? String {
            
            let fx = CGFloat.init(Float.init(x)!)
            let fy = CGFloat.init(Float.init(y)!)
            let fwidth = CGFloat.init(Float.init(width)!)
            let rect = CGRect(x: fx, y: fy, width: fwidth, height: fwidth)
            
            if type == "local" {
//                txCloudManager.setWatermark(UIImage.init(contentsOfFile: self.getFlutterBundlePath(assetPath: imageUrl)!), streamType: TRTCVideoStreamType.init(rawValue: streamType)!, rect: rect)
            } else {
                let queue = DispatchQueue(label: "setWatermark")
                queue.async {
                    let url: NSURL = NSURL(string: imageUrl)!
                    let data: NSData = NSData(contentsOf: url as URL)!
                    let img = UIImage(data: data as Data, scale: 1)!
                    self.txCloudManager.setWatermark(img, streamType: TRTCVideoStreamType.init(rawValue: streamType)!, rect: rect)
                }
            }
            
            result(nil);
        }
    }
    
  @objc(startScreenCaptureInApp:withResolver:withRejecter:)
    func startScreenCaptureInApp(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let encParams = param["encParams"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: encParams);
            let data = TRTCVideoEncParam();
            if dict["videoResolution"] != nil {
                data.videoResolution = TRTCVideoResolution(rawValue: dict["videoResolution"] as! Int)!;
            }
            if dict["videoFps"] != nil {
                data.videoFps = dict["videoFps"] as! Int32;
            }
            if dict["videoBitrate"] != nil {
                data.videoBitrate = dict["videoBitrate"] as! Int32;
            }
            if dict["enableAdjustRes"] != nil {
                data.enableAdjustRes = dict["enableAdjustRes"] as! Bool;
            }
            if #available(iOS 13.0,*){
                txCloudManager.startScreenCapture(inApp:data);
            }
        }else{
            if #available(iOS 13.0,*){
                //txCloudManager.startScreenCapture(inApp:nil);
            }
        }
        result(nil);
    }

  @objc(startScreenCaptureByReplaykit:withResolver:withRejecter:)
    func startScreenCaptureByReplaykit(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        let appGroup = param["appGroup"] as! String;
        if let encParams = param["encParams"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: encParams);
            let data = TRTCVideoEncParam();
            if dict["videoResolution"] != nil {
                data.videoResolution = TRTCVideoResolution(rawValue: dict["videoResolution"] as! Int)!;
            }
            if dict["videoFps"] != nil {
                data.videoFps = dict["videoFps"] as! Int32;
            }
            if dict["videoBitrate"] != nil {
                data.videoBitrate = dict["videoBitrate"] as! Int32;
            }
            if dict["enableAdjustRes"] != nil {
                data.enableAdjustRes = dict["enableAdjustRes"] as! Bool;
            }
            if #available(iOS 11.0,*){
                txCloudManager.startScreenCapture(byReplaykit:data,appGroup:appGroup);
            }
        }else{
            if #available(iOS 11.0,*){
                //txCloudManager.startScreenCapture(byReplaykit:nil,appGroup:appGroup);
            }
        }
        result(nil);
    }

  @objc(startScreenCapture:withResolver:withRejecter:)
    func startScreenCapture(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        //txCloudManager.startScreenCapture();
        result(nil);
    }

  @objc(stopScreenCapture:withResolver:withRejecter:)
    func stopScreenCapture(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if #available(iOS 11.0,*){
            result(txCloudManager.stopScreenCapture());
        }else{
            result(-1)
        }
    }

  @objc(pauseScreenCapture:withResolver:withRejecter:)
    func pauseScreenCapture(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if #available(iOS 11.0,*){
            result(txCloudManager.pauseScreenCapture());
        }else{
            result(-1)
        }
    }

  @objc(resumeScreenCapture:withResolver:withRejecter:)
    func resumeScreenCapture(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if #available(iOS 11.0,*){
            result(txCloudManager.resumeScreenCapture());
        }else{
            result(-1)
        }
    }

  @objc(sendCustomCmdMsg:withResolver:withRejecter:)
    func sendCustomCmdMsg(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let cmdID = param["cmdID"] as? Int,
           let dataStr = param["data"] as? String,
           let reliable = param["reliable"] as? Bool,
           let ordered = param["ordered"] as? Bool {
            let nsdata = dataStr.data(using: String.Encoding.utf8);
            result(txCloudManager.sendCustomCmdMsg(cmdID, data: nsdata!, reliable: reliable, ordered: ordered));
        }
    }
    
  @objc(sendSEIMsg:withResolver:withRejecter:)
    func sendSEIMsg(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if  let message = param["message"] as? String,
            let repeatCount = param["repeatCount"] as? Int32 {
            let nsdata = message.data(using: String.Encoding.utf8);
            result(txCloudManager.sendSEIMsg(nsdata!, repeatCount: repeatCount));
        }
    }

  @objc(startSpeedTest:withResolver:withRejecter:)
    func startSpeedTest(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let expectedDownBandwidth = param["expectedDownBandwidth"] as? Int,
           let expectedUpBandwidth = param["expectedUpBandwidth"] as? Int,
           let scene = param["scene"] as? UInt32,
           let sdkAppId = param["sdkAppId"] as? UInt32,
           let userId = param["userId"] as? String,
           let userSig = param["userSig"] as? String {
            let testParams: TRTCSpeedTestParams = TRTCSpeedTestParams();
            testParams.expectedDownBandwidth = expectedDownBandwidth;
            testParams.expectedUpBandwidth = expectedUpBandwidth;
            testParams.scene = transScene(scene: scene);
            testParams.sdkAppId = sdkAppId;
            testParams.userId = userId;
            testParams.userSig = userSig;
            txCloudManager.startSpeedTest(testParams);
            result(nil);
            
        }
    }

  @objc(stopSpeedTest:withRejecter:)
    func stopSpeedTest(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.stopSpeedTest();
        result(nil);
    }

    
  @objc(callExperimentalAPI:withResolver:withRejecter:)
  func callExperimentalAPI(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
      if let jsonStr = param["jsonStr"] as? String {
          txCloudManager.callExperimentalAPI(jsonStr);
          result(nil);
      }
  }
    // kamar xxx
    // sdk manager end
    // audio begin
    @objc(startPlayMusic:withResolver:withRejecter:)
      public func startPlayMusic(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let musicParam = param["musicParam"] as? String {
              let musicParam = JsonUtil.getDictionaryFromJSONString(jsonString: musicParam);
              let param = TXAudioMusicParam();
              
              param.id = musicParam["id"] as! Int32
              param.path = musicParam["path"] as! String
              param.loopCount = musicParam["loopCount"] as? Int ?? 0
              param.publish = musicParam["publish"] as? Bool ?? false
              param.isShortFile = musicParam["isShortFile"] as? Bool ?? false
              param.startTimeMS = musicParam["startTimeMS"] as? Int ?? 0
              param.endTimeMS = musicParam["endTimeMS"] as? Int ?? 0
              
              txAudioEffectManager.startPlayMusic(param, onStart: {
                  (errCode) -> Void in
                  
                self.sendEventFormat(name: "onMusicObserverStart", params: ["id": param.id, "errCode": errCode]);
              }, onProgress: {
                  (progressMs, durationMs) -> Void in
                  
                self.sendEventFormat(name: "onMusicObserverPlayProgress", params: ["id": param.id, "curPtsMS": progressMs, "durationMS": durationMs]);
              }, onComplete: {
                  (errCode) -> Void in
                
                self.sendEventFormat(name: "onMusicObserverComplete", params: ["id": param.id, "errCode": errCode]);
              });
              result(nil);
          }
      }
    
    @objc(startLocalRecording:withResolver:withRejecter:)
    public func startLocalRecording(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        if let param = param["param"] as? String {
            let dict = JsonUtil.getDictionaryFromJSONString(jsonString: param);
            let param = TRTCLocalRecordingParams();
            
            if dict["filePath"] != nil && !(dict["filePath"] is NSNull) {
                param.filePath = dict["filePath"] as! String;
            }
            if dict["recordType"] != nil && !(dict["recordType"] is NSNull) {
                let recordTypeValue = dict["recordType"] as! Int;
                param.recordType = TRTCRecordType(rawValue: UInt(recordTypeValue)) ?? TRTCRecordType(rawValue: 2)!;
            }
            if dict["interval"] != nil && !(dict["interval"] is NSNull) {
                param.interval = dict["interval"] as! Int32;
            }
            if dict["maxDurationPerFile"] != nil && !(dict["maxDurationPerFile"] is NSNull) {
                param.maxDurationPerFile = dict["maxDurationPerFile"] as! Int32;
            }
            
            txCloudManager.startLocalRecording(param);
            result(nil);
        }
    }
    
    @objc(stopLocalRecording:withRejecter:)
    public func stopLocalRecording(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
        txCloudManager.stopLocalRecording();
        result(nil);
    }

    @objc(enableVoiceEarMonitor:withResolver:withRejecter:)
      public func enableVoiceEarMonitor(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let enable = param["enable"] as? Bool {
              txAudioEffectManager.enableVoiceEarMonitor(enable);
              result(nil);
          }
      }

    @objc(setVoiceEarMonitorVolume:withResolver:withRejecter:)
      public func setVoiceEarMonitorVolume(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let volume = param["volume"] as? Int {
              txAudioEffectManager.setVoiceEarMonitorVolume(volume);
              result(nil);
          }
      }

    @objc(setVoiceReverbType:withResolver:withRejecter:)
      public func setVoiceReverbType(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let type = param["type"] as? Int {
              txAudioEffectManager.setVoiceReverbType(TXVoiceReverbType(rawValue: type)!);
              result(nil);
          }
      }

    @objc(setVoiceChangerType:withResolver:withRejecter:)
      public func setVoiceChangerType(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let type = param["type"] as? Int {
              txAudioEffectManager.setVoiceChangerType(TXVoiceChangeType(rawValue: type)!);
              result(nil);
          }
      }

    @objc(setVoiceCaptureVolume:withResolver:withRejecter:)
      public func setVoiceCaptureVolume(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let volume = param["volume"] as? Int {
              txAudioEffectManager.setVoiceVolume(volume);
              result(nil);
          }
      }
      
    @objc(stopPlayMusic:withResolver:withRejecter:)
      public func stopPlayMusic(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let id = param["id"] as? Int32 {
              txAudioEffectManager.stopPlayMusic(id);
              result(nil);
          }
      }

    @objc(pausePlayMusic:withResolver:withRejecter:)
      public func pausePlayMusic(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let id = param["id"] as? Int32 {
              txAudioEffectManager.pausePlayMusic(id);
              result(nil);
          }
      }

    @objc(resumePlayMusic:withResolver:withRejecter:)
      public func resumePlayMusic(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let id = param["id"] as? Int32 {
              txAudioEffectManager.resumePlayMusic(id);
              result(nil);
          }
      }

    @objc(setMusicPublishVolume:withResolver:withRejecter:)
      public func setMusicPublishVolume(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let id = param["id"] as? Int32,
             let volume = param["volume"] as? Int {
              txAudioEffectManager.setMusicPublishVolume(id, volume: volume);
              result(nil);
          }
      }

    @objc(setMusicPlayoutVolume:withResolver:withRejecter:)
      public func setMusicPlayoutVolume(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let id = param["id"] as? Int32,
             let volume = param["volume"] as? Int {
              txAudioEffectManager.setMusicPlayoutVolume(id, volume: volume);
              result(nil);
          }
      }

    @objc(setAllMusicVolume:withResolver:withRejecter:)
      public func setAllMusicVolume(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let volume = param["volume"] as? Int {
              txAudioEffectManager.setAllMusicVolume(volume);
              result(nil);
          }
      }

    @objc(setMusicPitch:withResolver:withRejecter:)
      public func setMusicPitch(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let volume = param["volume"] as? Int32,
             let pitch = Double.init((param["pitch"] as? String)!) {
              txAudioEffectManager.setMusicPitch(volume, pitch: pitch);
              result(nil);
          }
      }

    @objc(setMusicSpeedRate:withResolver:withRejecter:)
      public func setMusicSpeedRate(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let id = param["id"] as? Int32,
             let speedRate = Double.init((param["speedRate"] as? String)!) {
              txAudioEffectManager.setMusicSpeedRate(id, speedRate: speedRate);
              result(nil);
          }
      }

    @objc(getMusicCurrentPosInMS:withResolver:withRejecter:)
      public func getMusicCurrentPosInMS(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let id = param["id"] as? Int32 {
              let ms = txAudioEffectManager.getMusicCurrentPos(inMS: id);
              result(ms);
          }
      }

    @objc(seekMusicToPosInMS:withResolver:withRejecter:)
      public func seekMusicToPosInMS(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          if let id = param["id"] as? Int32,
             let pts = param["pts"] as? Int {
              txAudioEffectManager.seekMusicToPos(inMS: id, pts: pts);
              result(nil);
          }
      }

    @objc(getMusicDurationInMS:withResolver:withRejecter:)
      public func getMusicDurationInMS(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
          let path = ["path"] as? String
          let res = txAudioEffectManager.getMusicDuration(inMS: path != nil ? path! : "");
          result(res);
      }
    // audio end
//    device 
      @objc(switchCamera:withResolver:withRejecter:)
        func switchCamera(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let isFrontCamera = param["isFrontCamera"] as? Bool {
                txDeviceManager.switchCamera(isFrontCamera);
                result(nil);
            }
        }

      @objc(isFrontCamera:withRejecter:)
        func isFrontCamera(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            result(txDeviceManager.isFrontCamera());
        }

      @objc(getCameraZoomMaxRatio:withRejecter:)
        func getCameraZoomMaxRatio(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            result(Int(txDeviceManager.getCameraZoomMaxRatio()));
        }

      @objc(setCameraZoomRatio:withResolver:withRejecter:)
        func setCameraZoomRatio(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let value = param["value"] as? String {
                let ret = txDeviceManager.setCameraZoomRatio(CGFloat(Int(Float(value)!)));
                result(ret);
            }
        }

      @objc(enableCameraAutoFocus:withResolver:withRejecter:)
        func enableCameraAutoFocus(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let enable = param["enable"] as? Bool {
                result(txDeviceManager.enableCameraAutoFocus(enable));
            }
        }

      @objc(enableCameraTorch:withResolver:withRejecter:)
        func enableCameraTorch(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let enable = param["enable"] as? Bool {
                txDeviceManager.enableCameraTorch(enable);
                result(nil);
            }
        }

      @objc(setCameraFocusPosition:withResolver:withRejecter:)
        func setCameraFocusPosition(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let x = param["x"] as? Int,
               let y = param["y"] as? Int {
                txDeviceManager.setCameraFocusPosition(CGPoint(x: CGFloat(x), y: CGFloat(y)));
                result(nil);
            }
        }

      @objc(isAutoFocusEnabled:withRejecter:)
        func isAutoFocusEnabled(result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            result(txDeviceManager.isAutoFocusEnabled());
        }
        
      @objc(setSystemVolumeType:withResolver:withRejecter:)
        func setSystemVolumeType(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let type = param["type"] as? Int {
                txDeviceManager.setSystemVolumeType(TXSystemVolumeType(rawValue: type)!);
                result(nil);
            }
        }

      @objc(setAudioRoute:withResolver:withRejecter:)
        func setAudioRoute(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let route = param["route"] as? Int {
                txDeviceManager.setAudioRoute(TXAudioRoute(rawValue: route)!);
                result(nil);
            }
        }
//    device end

// beauty manager 
        @objc(setBeautyStyle:withResolver:withRejecter:)
        func setBeautyStyle(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let beautyStyle = param["beautyStyle"] as? Int {
                txBeautyManager.setBeautyStyle(TXBeautyStyle(rawValue: beautyStyle)!);
                result(nil);
            }
        }
        
        @objc(setFilter:withResolver:withRejecter:)
        func setFilter(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let imageUrl = param["imageUrl"] as? String {
//                let img = NSImage(contentsOfFile:self.getFlutterBundlePath(assetPath:imageUrl)!)!;
//                txBeautyManager.setFilter(img);
                if(imageUrl == "") {
                    self.txBeautyManager.setFilter(nil);
                } else {
                    let queue = DispatchQueue(label: "setFilter")
                    queue.async {
                        let url: NSURL = NSURL(string: imageUrl)!
                        let data: NSData = NSData(contentsOf: url as URL)!
                        let img = UIImage(data: data as Data, scale: 1)!
                        self.txBeautyManager.setFilter(img);
                    }
                }
                result(nil);
            }
        }

        @objc(setFilterStrength:withResolver:withRejecter:)
        func setFilterStrength(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let strength = param["strength"] as? String {
                txBeautyManager.setFilterStrength(Float(strength)!);
                result(nil);
            }
        }
        
        @objc(setBeautyLevel:withResolver:withRejecter:)
        func setBeautyLevel(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let beautyLevel = param["beautyLevel"] as? Int {
                txBeautyManager.setBeautyLevel(Float(beautyLevel));
                result(nil);
            }
        }
        
        @objc(setWhitenessLevel:withResolver:withRejecter:)
        func setWhitenessLevel(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let whitenessLevel = param["whitenessLevel"] as? Int {
                txBeautyManager.setWhitenessLevel(Float(whitenessLevel));
                result(nil);
            }
        }
        
        @objc(setRuddyLevel:withResolver:withRejecter:)
        func setRuddyLevel(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let ruddyLevel = param["ruddyLevel"] as? Float {
                txBeautyManager.setRuddyLevel(ruddyLevel);
                result(nil);
            }
        }
        
        @objc(enableSharpnessEnhancement:withResolver:withRejecter:)
        func enableSharpnessEnhancement(param: NSDictionary, result: @escaping RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
            if let enable = param["enable"] as? Bool {
                txBeautyManager.enableSharpnessEnhancement(enable);
                result(nil);
            }
        }
    
// beauty manager end
    
    // Listener begin
    public func sendEventFormat(name: String, params: Any?) {
        sendEvent(withName: "onListener", body: ["type": name, "params": params]);
    }
    
    public func onError(_ errCode: TXLiteAVError, errMsg: String?, extInfo: [AnyHashable: Any]?) {
        sendEventFormat(name: "onError", params: ["errCode": errCode.rawValue, "errMsg": errMsg ?? "", "extraInfo": extInfo as Any]);
    }

    public func onWarning(_ warningCode: TXLiteAVWarning, warningMsg: String?, extInfo: [AnyHashable: Any]?) {
        sendEventFormat(name: "onWarning", params: ["warningCode": warningCode.rawValue, "warningMsg": warningMsg  ?? "", "extraInfo": extInfo as Any]);
    }

    public func onEnterRoom(_ result: Int) {
        sendEventFormat(name: "onEnterRoom", params: ["result": result]);
    }

    public func onExitRoom(_ reason: Int) {
        sendEventFormat(name: "onExitRoom", params: ["reason": reason]);
    }

    public func onSwitchRole(_ errCode: TXLiteAVError, errMsg: String?) {
        sendEventFormat(name: "onSwitchRole", params: ["errCode": errCode.rawValue, "errMsg": errMsg ?? ""]);
    }

    public func onConnectOtherRoom(_ userId: String, errCode: TXLiteAVError, errMsg: String?) {
        sendEventFormat(name: "onConnectOtherRoom", params: ["userId": userId, "errCode": errCode.rawValue, "errMsg": errMsg ?? ""]);
    }

    public func onSwitchRoom(_ errCode: TXLiteAVError, errMsg: String?) {
        sendEventFormat(name: "onSwitchRoom", params: ["errCode": errCode.rawValue, "errMsg": errMsg ?? ""]);
    }

    public func onDisconnectOtherRoom(_ errCode: TXLiteAVError, errMsg: String?) {
        sendEventFormat(name: "onDisConnectOtherRoom", params: ["errCode": errCode.rawValue, "errMsg": errMsg ?? ""]);
    }

    public func onRemoteUserEnterRoom(_ userId: String) {
        sendEventFormat(name: "onRemoteUserEnterRoom", params: ["userId": userId]);
    }

    public func onRemoteUserLeaveRoom(_ userId: String, reason: Int) {
        sendEventFormat(name: "onRemoteUserLeaveRoom", params: ["userId": userId, "reason": reason]);
    }

    public func onUserVideoAvailable(_ userId: String, available: Bool) {
        sendEventFormat(name: "onUserVideoAvailable", params: ["userId": userId, "available": available]);
    }

    public func onUserSubStreamAvailable(_ userId: String, available: Bool) {
        sendEventFormat(name: "onUserSubStreamAvailable", params: ["userId": userId, "available": available]);
    }

    public func onUserAudioAvailable(_ userId: String, available: Bool) {
        sendEventFormat(name: "onUserAudioAvailable", params: ["userId": userId, "available": available]);
    }

    public func onFirstVideoFrame(_ userId: String, streamType: TRTCVideoStreamType, width: Int32, height: Int32) {
        sendEventFormat(name: "onFirstVideoFrame", params: ["userId": userId, "streamType": streamType.rawValue, "width": width, "height": height]);
    }

    public func onUserVideoSizeChanged(_ userId: String, streamType: TRTCVideoStreamType, newWidth: Int32, newHeight: Int32) {
        sendEventFormat(name: "onUserVideoSizeChanged", params: ["userId": userId, "streamType": streamType.rawValue, "newWidth": newWidth, "newHeight": newHeight]);
    }

    public func onFirstAudioFrame(_ userId: String) {
        sendEventFormat(name: "onFirstAudioFrame", params: ["userId": userId]);
    }

    public func onSendFirstLocalVideoFrame(_ streamType: TRTCVideoStreamType) {
        sendEventFormat(name: "onSendFirstLocalVideoFrame", params: ["streamType": streamType.rawValue]);
    }

    public func onSendFirstLocalAudioFrame() {
        sendEventFormat(name: "onSendFirstLocalAudioFrame", params: nil);
    }

    public func onNetworkQuality(_ localQuality: TRTCQualityInfo, remoteQuality: [TRTCQualityInfo]) {
        var array: [Any] = [];
        
        for item in remoteQuality {
            array.append(["userId": item.userId as Any, "quality": item.quality.rawValue]);
        }
        
        sendEventFormat(name: "onNetworkQuality", params: [
            "localQuality": [
                "userId": localQuality.userId as Any,
                "quality": localQuality.quality.rawValue
            ],
            "remoteQuality": array
        ]);
    }

    public func onStatistics(_ statistics: TRTCStatistics) {
        var localArray: [Any] = [];
        var remoteArray: [Any] = [];
        
        for item in statistics.localStatistics {
            localArray.append([
                "width": item.width,
                "height": item.height,
                "frameRate": item.frameRate,
                "videoBitrate": item.videoBitrate,
                "audioSampleRate": item.audioSampleRate,
                "audioBitrate": item.audioBitrate,
                "streamType": item.streamType.rawValue
            ]);
        }
        
        for item in statistics.remoteStatistics {
            remoteArray.append([
                "userId": item.userId as Any,
                "finalLoss": item.finalLoss,
                "width": item.width,
                "height": item.height,
                "frameRate": item.frameRate,
                "videoBitrate": item.videoBitrate,
                "audioSampleRate": item.audioSampleRate,
                "audioBitrate": item.audioBitrate,
                "jitterBufferDelay": item.jitterBufferDelay,
                "audioTotalBlockTime": item.audioTotalBlockTime,
                "audioBlockRate": item.audioBlockRate,
                "videoTotalBlockTime": item.videoTotalBlockTime,
                "videoBlockRate": item.videoBlockRate,
                "streamType": item.streamType.rawValue
            ]);
        }
        sendEventFormat(name: "onStatistics", params: [
            "upLoss": statistics.upLoss,
            "downLoss": statistics.downLoss,
            "appCpu": statistics.appCpu,
            "systemCpu": statistics.systemCpu,
            "rtt": statistics.rtt,
            "receivedBytes": statistics.receivedBytes,
            "sendBytes": statistics.sentBytes,
            "localArray": localArray,
            "remoteArray": remoteArray
        ]);
    }
    
    public func onSpeedTestResult(_ result: TRTCSpeedTestResult) {
        sendEventFormat(name: "onSpeedTestResult", params: [
            "success": result.success,
            "availableUpBandwidth": result.availableUpBandwidth,
            "availableDownBandwidth": result.availableDownBandwidth,
            "downJitter": result.downJitter,
            "downLostRate": result.downLostRate,
            "errMsg": result.errMsg,
            "ip": result.ip,
            "quality": result.quality.rawValue,
            "rtt": result.rtt,
            "upJitter": result.upJitter,
            "upLostRate": result.upLostRate
        ]);
    }
    
    public func onConnectionLost() {
        sendEventFormat(name: "onConnectionLost", params: nil);
    }

    public func onTryToReconnect() {
        sendEventFormat(name: "onTryToReconnect", params: nil);
    }

    public func onConnectionRecovery() {
        sendEventFormat(name: "onConnectionRecovery", params: nil);
    }
    
    public func onCameraDidReady() {
        sendEventFormat(name: "onCameraDidReady", params: nil);
    }

    public func onMicDidReady() {
        sendEventFormat(name: "onMicDidReady", params: nil);
    }

    public func onAudioRouteChanged(_ route: TRTCAudioRoute, from fromRoute: TRTCAudioRoute) {
        sendEventFormat(name: "onAudioRouteChanged", params: ["newRoute": route.rawValue, "oldRoute": fromRoute.rawValue]);
    }
    

    public func onUserVoiceVolume(_ userVolumes: [TRTCVolumeInfo], totalVolume: Int) {
        var userVolumeArray: [Any] = [];
        for item in userVolumes {
            userVolumeArray.append([
                "userId": (item.userId == nil) ? "" : (item.userId!),
                "volume": item.volume
            ]);
        }
        
        sendEventFormat(name: "onUserVoiceVolume", params: ["userVolumes": userVolumeArray, "totalVolume": totalVolume]);
    }
    
    public func onRecvCustomCmdMsgUserId(_ userId: String, cmdID: Int, seq: UInt32, message: Data) {
        sendEventFormat(name: "onRecvCustomCmdMsg", params: [
            "userId": userId,
            "cmdID": cmdID,
            "seq": seq,
            "message": (String(data: message, encoding: String.Encoding.utf8) as String?) ?? ""
        ]);
    }

    public func onMissCustomCmdMsgUserId(_ userId: String, cmdID: Int, errCode: Int, missed: Int) {
        sendEventFormat(name: "onMissCustomCmdMsg", params: [
            "userId": userId,
            "cmdID": cmdID,
            "errCode": errCode,
            "missed": missed
        ]);
    }

    public func onRecvSEIMsg(_ userId: String, message: Data) {
        sendEventFormat(name: "onRecvSEIMsg", params: [
            "userId": userId,
            "message": (String(data: message, encoding: String.Encoding.utf8) as String?) ?? ""
        ]);
    }

    public func onStartPublishing(_ err: Int32, errMsg: String) {
        sendEventFormat(name: "onStartPublishing", params: [
            "errCode": err,
            "errMsg": errMsg
        ]);
    }
    
    public func onStopPublishing(_ err: Int32, errMsg: String) {
        sendEventFormat(name: "onStopPublishing", params: [
            "errCode": err,
            "errMsg": errMsg
        ]);
    }
    
    public func onStartPublishCDNStream(_ err: Int32, errMsg: String) {
        sendEventFormat(name: "onStartPublishCDNStream", params: [
            "errCode": err,
            "errMsg": errMsg
        ]);
    }

    public func onStopPublishCDNStream(_ err: Int32, errMsg: String) {
        sendEventFormat(name: "onStopPublishCDNStream", params: [
            "errCode": err,
            "errMsg": errMsg
        ]);
    }

    public func onSetMixTranscodingConfig(_ err: Int32, errMsg: String) {
        sendEventFormat(name: "onSetMixTranscodingConfig", params: [
            "errCode": err,
            "errMsg": errMsg
        ]);
    }
    
    public func onAudioEffectFinished(_ effectId: Int32, code: Int32) {
        sendEventFormat(name: "onAudioEffectFinished", params: [
            "effectId": effectId,
            "errCode": code
        ]);
    }

    public func onScreenCaptureStarted() {
        sendEventFormat(name: "onScreenCaptureStarted", params:nil);
    }

    public func onScreenCapturePaused(_ reason:Int32) {
        sendEventFormat(name: "onScreenCapturePaused", params:reason);
    }

    public func onScreenCaptureResumed(_ reason:Int32) {
        sendEventFormat(name: "onScreenCaptureResumed", params:reason);
    }

    public func onScreenCaptureStoped(_ reason:Int32) {
        sendEventFormat(name: "onScreenCaptureStoped", params:reason);
    }
    // Listener end
    
    private func transScene(scene: UInt32)-> TRTCSpeedTestScene {
        switch(scene) {
        case 1:
            return TRTCSpeedTestScene(rawValue: 1) ?? .delayTesting
        case 2:
            return TRTCSpeedTestScene(rawValue: 2) ?? .delayAndBandwidthTesting
        default:
            return TRTCSpeedTestScene(rawValue: 3) ?? .onlineChorusTesting
        }
    }
}
