diff --git a/android/src/main/java/io/agora/agorartcengine/AgoraRtcEnginePlugin.java b/android/src/main/java/io/agora/agorartcengine/AgoraRtcEnginePlugin.java index 3f5385d92..c8d1d580f 100644 --- a/android/src/main/java/io/agora/agorartcengine/AgoraRtcEnginePlugin.java +++ b/android/src/main/java/io/agora/agorartcengine/AgoraRtcEnginePlugin.java @@ -1,11 +1,5 @@ package io.agora.agorartcengine; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugin.common.MethodChannel.Result; -import io.flutter.plugin.common.PluginRegistry.Registrar; - import android.content.Context; import android.graphics.Rect; import android.os.Handler; @@ -14,966 +8,1021 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import io.agora.rtc.RtcEngine; import io.agora.rtc.IRtcEngineEventHandler; +import io.agora.rtc.RtcEngine; +import io.agora.rtc.video.BeautyOptions; import io.agora.rtc.video.VideoCanvas; import io.agora.rtc.video.VideoEncoderConfiguration; -import io.agora.rtc.video.BeautyOptions; - +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.PluginRegistry.Registrar; import io.flutter.plugin.common.StandardMessageCodec; -/** AgoraRtcEnginePlugin */ +/** + * AgoraRtcEnginePlugin + */ public class AgoraRtcEnginePlugin implements MethodCallHandler { - private final Registrar mRegistrar; - private final MethodChannel mMethodChannel; - private RtcEngine mRtcEngine; - private HashMap mRendererViews; - private Handler mEventHandler = new Handler(Looper.getMainLooper()); - - void addView(SurfaceView view, int id) { - mRendererViews.put("" + id, view); - } - - private void removeView(int id) { - mRendererViews.remove("" + id); - } - - private SurfaceView getView(int id) { - return mRendererViews.get("" + id); - } - - /** Plugin registration. */ - public static void registerWith(Registrar registrar) { - final MethodChannel channel = new MethodChannel(registrar.messenger(), "agora_rtc_engine"); - - AgoraRtcEnginePlugin plugin = new AgoraRtcEnginePlugin(registrar, channel); - channel.setMethodCallHandler(plugin); - - AgoraRenderViewFactory fac = new AgoraRenderViewFactory(StandardMessageCodec.INSTANCE, plugin); - registrar.platformViewRegistry().registerViewFactory("AgoraRendererView", fac); - } - - private AgoraRtcEnginePlugin(Registrar registrar, MethodChannel channel) { - this.mRegistrar = registrar; - this.mMethodChannel = channel; - this.mRendererViews = new HashMap<>(); - } - - private Context getActiveContext() { - return (mRegistrar.activity() != null) ? mRegistrar.activity() : mRegistrar.context(); - } - - @Override - public void onMethodCall(MethodCall call, Result rawResult) { - Context context = getActiveContext(); - MethodChannel.Result result = new MethodResultWrapper(rawResult, mEventHandler); - - switch (call.method) { - // Core Methods - case "create": { - try { - String appId = call.argument("appId"); - mRtcEngine = RtcEngine.create(context, appId, mRtcEventHandler); - } catch (Exception e) { - throw new RuntimeException("NEED TO check rtc sdk init fatal error\n"); - } - } - break; - case "destroy": { - RtcEngine.destroy(); - } - break; - case "setChannelProfile": { - int profile = call.argument("profile"); - mRtcEngine.setChannelProfile(profile); - } - break; - case "setClientRole": { - int role = call.argument("role"); - mRtcEngine.setClientRole(role); - } - break; - case "joinChannel": { - String token = call.argument("token"); - String channel = call.argument("channelId"); - String info = call.argument("info"); - int uid = call.argument("uid"); - mRtcEngine.joinChannel(token, channel, info, uid); - } - break; - case "leaveChannel": { - mRtcEngine.leaveChannel(); - } - break; - case "renewToken": { - String token = call.argument("token"); - mRtcEngine.renewToken(token); - } - break; - case "enableWebSdkInteroperability": { - boolean enabled = call.argument("enabled"); - mRtcEngine.enableWebSdkInteroperability(enabled); - } - break; - case "getConnectionState": { - int state = mRtcEngine.getConnectionState(); - result.success(state); - } - break; - // Core Audio - case "enableAudio": { - mRtcEngine.enableAudio(); - } - break; - case "disableAudio": { - mRtcEngine.disableAudio(); - } - break; - case "setAudioProfile": { - int profile = call.argument("profile"); - int scenario = call.argument("scenario"); - mRtcEngine.setAudioProfile(profile, scenario); - } - break; - case "adjustRecordingSignalVolume": { - int volume = call.argument("volume"); - mRtcEngine.adjustRecordingSignalVolume(volume); - } - break; - case "adjustPlaybackSignalVolume": { - int volume = call.argument("volume"); - mRtcEngine.adjustPlaybackSignalVolume(volume); - } - break; - case "enableAudioVolumeIndication": { - int interval = call.argument("interval"); - int smooth = call.argument("smooth"); - mRtcEngine.enableAudioVolumeIndication(interval, smooth); - } - break; - case "enableLocalAudio": { - boolean enabled = call.argument("enabled"); - mRtcEngine.enableLocalAudio(enabled); - } - break; - case "muteLocalAudioStream": { - boolean muted = call.argument("muted"); - mRtcEngine.muteLocalAudioStream(muted); - } - break; - case "muteRemoteAudioStream": { - int uid = call.argument("uid"); - boolean muted = call.argument("muted"); - mRtcEngine.muteRemoteAudioStream(uid, muted); - } - break; - case "muteAllRemoteAudioStreams": { - boolean muted = call.argument("muted"); - mRtcEngine.muteAllRemoteAudioStreams(muted); - } - break; - case "setDefaultMuteAllRemoteAudioStreams": { - boolean muted = call.argument("muted"); - mRtcEngine.setDefaultMuteAllRemoteAudioStreams(muted); - } - break; - // Video Pre-process and Post-process - case "setBeautyEffectOptions": { - boolean enabled = call.argument("enabled"); - HashMap optionsMap = call.argument("options"); - BeautyOptions options = beautyOptionsFromMap(optionsMap); - mRtcEngine.setBeautyEffectOptions(enabled, options); - } - break; - // Core Video - case "enableVideo": { - mRtcEngine.enableVideo(); - } - break; - case "disableVideo": { - mRtcEngine.disableVideo(); - } - break; - case "setVideoEncoderConfiguration": { - HashMap configDic = call.argument("config"); - VideoEncoderConfiguration config = videoEncoderConfigurationFromMap(configDic); - mRtcEngine.setVideoEncoderConfiguration(config); - } - break; - case "removeNativeView": { - int viewId = call.argument("viewId"); - removeView(viewId); - } - break; - case "setupLocalVideo": { - int localViewId = call.argument("viewId"); - SurfaceView localView = getView(localViewId); - int localRenderMode = call.argument("renderMode"); - VideoCanvas localCanvas = new VideoCanvas(localView); - localCanvas.renderMode = localRenderMode; - mRtcEngine.setupLocalVideo(localCanvas); - } - break; - case "setupRemoteVideo": { - int remoteViewId = call.argument("viewId"); - SurfaceView view = getView(remoteViewId); - int remoteRenderMode = call.argument("renderMode"); - int remoteUid = call.argument("uid"); - mRtcEngine.setupRemoteVideo(new VideoCanvas(view, remoteRenderMode, remoteUid)); - } - break; - case "setLocalRenderMode": { - int mode = call.argument("mode"); - mRtcEngine.setLocalRenderMode(mode); - } - break; - case "setRemoteRenderMode": { - int uid = call.argument("uid"); - int mode = call.argument("mode"); - mRtcEngine.setRemoteRenderMode(uid, mode); - } - break; - case "startPreview": { - mRtcEngine.startPreview(); - } - break; - case "stopPreview": { - mRtcEngine.stopPreview(); - } - break; - case "enableLocalVideo": { - boolean enabled = call.argument("enabled"); - mRtcEngine.enableLocalVideo(enabled); - } - break; - case "muteLocalVideoStream": { - boolean muted = call.argument("muted"); - mRtcEngine.muteLocalVideoStream(muted); - } - break; - case "muteRemoteVideoStream": { - int uid = call.argument("uid"); - boolean muted = call.argument("muted"); - mRtcEngine.muteRemoteVideoStream(uid, muted); - } - break; - case "muteAllRemoteVideoStreams": { - boolean muted = call.argument("muted"); - mRtcEngine.muteAllRemoteVideoStreams(muted); - } - break; - case "setDefaultMuteAllRemoteVideoStreams": { - boolean muted = call.argument("muted"); - mRtcEngine.setDefaultMuteAllRemoteVideoStreams(muted); - } - break; - - // Audio Routing Controller - case "setDefaultAudioRouteToSpeaker": { - boolean defaultToSpeaker = call.argument("defaultToSpeaker"); - mRtcEngine.setDefaultAudioRoutetoSpeakerphone(defaultToSpeaker); - } - break; - case "setEnableSpeakerphone": { - boolean enabled = call.argument("enabled"); - mRtcEngine.setEnableSpeakerphone(enabled); - } - break; - case "isSpeakerphoneEnabled": { - boolean enabled = mRtcEngine.isSpeakerphoneEnabled(); - result.success(enabled); - } - break; - - // Stream Fallback - case "setRemoteUserPriority": { - int uid = call.argument("uid"); - int userPriority = call.argument("userPriority"); - mRtcEngine.setRemoteUserPriority(uid, userPriority); - } - case "setLocalPublishFallbackOption": { - int option = call.argument("option"); - mRtcEngine.setLocalPublishFallbackOption(option); - } - break; - case "setRemoteSubscribeFallbackOption": { - int option = call.argument("option"); - mRtcEngine.setRemoteSubscribeFallbackOption(option); - } - break; - - // Dual-stream Mode - case "enableDualStreamMode": { - boolean enabled = call.argument("enabled"); - mRtcEngine.enableDualStreamMode(enabled); - } - break; - case "setRemoteVideoStreamType": { - int uid = call.argument("uid"); - int streamType = call.argument("streamType"); - mRtcEngine.setRemoteVideoStreamType(uid, streamType); - } - break; - case "setRemoteDefaultVideoStreamType": { - int streamType = call.argument("streamType"); - mRtcEngine.setRemoteDefaultVideoStreamType(streamType); - } - break; - - // Encryption - case "setEncryptionSecret": { - String secret = call.argument("secret"); - mRtcEngine.setEncryptionSecret(secret); - } - break; - case "setEncryptionMode": { - String encryptionMode = call.argument("encryptionMode"); - mRtcEngine.setEncryptionMode(encryptionMode); - } - break; - - // Camera Control - case "switchCamera": { - mRtcEngine.switchCamera(); - } - break; - - // Miscellaneous Methods - case "getSdkVersion": { - String version = RtcEngine.getSdkVersion(); - result.success(version); - } - break; - - default: - result.notImplemented(); - } - } - - private VideoEncoderConfiguration.ORIENTATION_MODE orientationFromValue(int value) { - switch (value) { - case 0: - return VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE; - case 1: - return VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_LANDSCAPE; - case 2: - return VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT; - default: - return VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE; - } - } + private final Registrar mRegistrar; + private final MethodChannel mMethodChannel; + private RtcEngine mRtcEngine; + private HashMap mRendererViews; + private Handler mEventHandler = new Handler(Looper.getMainLooper()); - private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() { - @Override - public void onWarning(int warn) { - super.onWarning(warn); - HashMap map = new HashMap<>(); - map.put("warn", warn); - invokeMethod("onWarning", map); + void addView(SurfaceView view , int id) { + mRendererViews.put("" + id , view); } - @Override - public void onError(int err) { - super.onError(err); - HashMap map = new HashMap<>(); - map.put("err", err); - invokeMethod("onError", map); + private void removeView(int id) { + mRendererViews.remove("" + id); } - @Override - public void onJoinChannelSuccess(String channel, int uid, int elapsed) { - super.onJoinChannelSuccess(channel, uid, elapsed); - HashMap map = new HashMap<>(); - map.put("channel", channel); - map.put("uid", uid); - map.put("elapsed", elapsed); - invokeMethod("onJoinChannelSuccess", map); + private SurfaceView getView(int id) { + return mRendererViews.get("" + id); } - @Override - public void onRejoinChannelSuccess(String channel, int uid, int elapsed) { - super.onRejoinChannelSuccess(channel, uid, elapsed); - HashMap map = new HashMap<>(); - map.put("channel", channel); - map.put("uid", uid); - map.put("elapsed", elapsed); - invokeMethod("onRejoinChannelSuccess", map); - } + /** + * Plugin registration. + */ + public static void registerWith(Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger() , "agora_rtc_engine"); - @Override - public void onLeaveChannel(RtcStats stats) { - super.onLeaveChannel(stats); - HashMap map = new HashMap<>(); - map.put("stats", mapFromStats(stats)); - invokeMethod("onLeaveChannel", map); - } + AgoraRtcEnginePlugin plugin = new AgoraRtcEnginePlugin(registrar , channel); + channel.setMethodCallHandler(plugin); - @Override - public void onClientRoleChanged(int oldRole, int newRole) { - super.onClientRoleChanged(oldRole, newRole); - HashMap map = new HashMap<>(); - map.put("oldRole", oldRole); - map.put("newRole", newRole); - invokeMethod("onClientRoleChanged", map); + AgoraRenderViewFactory fac = new AgoraRenderViewFactory(StandardMessageCodec.INSTANCE , + plugin); + registrar.platformViewRegistry().registerViewFactory("AgoraRendererView" , fac); } - @Override - public void onUserJoined(int uid, int elapsed) { - super.onUserJoined(uid, elapsed); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("elapsed", elapsed); - invokeMethod("onUserJoined", map); + private AgoraRtcEnginePlugin(Registrar registrar , MethodChannel channel) { + this.mRegistrar = registrar; + this.mMethodChannel = channel; + this.mRendererViews = new HashMap<>(); } - @Override - public void onUserOffline(int uid, int reason) { - super.onUserOffline(uid, reason); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("reason", reason); - invokeMethod("onUserOffline", map); + private Context getActiveContext() { + return (mRegistrar.activity() != null) ? mRegistrar.activity() : mRegistrar.context(); } @Override - public void onConnectionStateChanged(int state, int reason) { - super.onConnectionStateChanged(state, reason); - HashMap map = new HashMap<>(); - map.put("state", state); - map.put("reason", reason); - invokeMethod("onConnectionStateChanged", map); + public void onMethodCall(MethodCall call , Result result) { + Context context = getActiveContext(); + // MethodChannel.Result result = new MethodResultWrapper(rawResult, mEventHandler); + // 本方法执行在主线程,result调用没有跨线程,无需再次发送 + + switch (call.method) { + // Core Methods + case "create": { + try { + String appId = call.argument("appId"); + mRtcEngine = RtcEngine.create(context , appId , mRtcEventHandler); + result.success(null); + } catch (Exception e) { + throw new RuntimeException("NEED TO check rtc sdk init fatal error\n"); + } + } + break; + case "destroy": { + RtcEngine.destroy(); + result.success(null); + } + break; + case "setChannelProfile": { + int profile = call.argument("profile"); + mRtcEngine.setChannelProfile(profile); + result.success(null); + } + break; + case "setClientRole": { + int role = call.argument("role"); + mRtcEngine.setClientRole(role); + result.success(null); + } + break; + case "joinChannel": { + String token = call.argument("token"); + String channel = call.argument("channelId"); + String info = call.argument("info"); + int uid = call.argument("uid"); + result.success(mRtcEngine.joinChannel(token , channel , info , uid) >= 0); + } + break; + case "leaveChannel": { + result.success(mRtcEngine.leaveChannel() >= 0); + } + break; + case "renewToken": { + String token = call.argument("token"); + mRtcEngine.renewToken(token); + result.success(null); + } + break; + case "enableWebSdkInteroperability": { + boolean enabled = call.argument("enabled"); + mRtcEngine.enableWebSdkInteroperability(enabled); + result.success(null); + } + break; + case "getConnectionState": { + int state = mRtcEngine.getConnectionState(); + result.success(state); + } + break; + // Core Audio + case "enableAudio": { + mRtcEngine.enableAudio(); + result.success(null); + } + break; + case "disableAudio": { + mRtcEngine.disableAudio(); + result.success(null); + } + break; + case "setAudioProfile": { + int profile = call.argument("profile"); + int scenario = call.argument("scenario"); + mRtcEngine.setAudioProfile(profile , scenario); + result.success(null); + } + break; + case "adjustRecordingSignalVolume": { + int volume = call.argument("volume"); + mRtcEngine.adjustRecordingSignalVolume(volume); + result.success(null); + } + break; + case "adjustPlaybackSignalVolume": { + int volume = call.argument("volume"); + mRtcEngine.adjustPlaybackSignalVolume(volume); + result.success(null); + } + break; + case "enableAudioVolumeIndication": { + int interval = call.argument("interval"); + int smooth = call.argument("smooth"); + mRtcEngine.enableAudioVolumeIndication(interval , smooth); + result.success(null); + } + break; + case "enableLocalAudio": { + boolean enabled = call.argument("enabled"); + mRtcEngine.enableLocalAudio(enabled); + result.success(null); + } + break; + case "muteLocalAudioStream": { + boolean muted = call.argument("muted"); + mRtcEngine.muteLocalAudioStream(muted); + result.success(null); + } + break; + case "muteRemoteAudioStream": { + int uid = call.argument("uid"); + boolean muted = call.argument("muted"); + mRtcEngine.muteRemoteAudioStream(uid , muted); + result.success(null); + } + break; + case "muteAllRemoteAudioStreams": { + boolean muted = call.argument("muted"); + mRtcEngine.muteAllRemoteAudioStreams(muted); + result.success(null); + } + break; + case "setDefaultMuteAllRemoteAudioStreams": { + boolean muted = call.argument("muted"); + mRtcEngine.setDefaultMuteAllRemoteAudioStreams(muted); + result.success(null); + } + break; + // Video Pre-process and Post-process + case "setBeautyEffectOptions": { + boolean enabled = call.argument("enabled"); + HashMap optionsMap = call.argument("options"); + BeautyOptions options = beautyOptionsFromMap(optionsMap); + mRtcEngine.setBeautyEffectOptions(enabled , options); + result.success(null); + } + break; + // Core Video + case "enableVideo": { + mRtcEngine.enableVideo(); + result.success(null); + } + break; + case "disableVideo": { + mRtcEngine.disableVideo(); + result.success(null); + } + break; + case "setVideoEncoderConfiguration": { + HashMap configDic = call.argument("config"); + VideoEncoderConfiguration config = videoEncoderConfigurationFromMap(configDic); + mRtcEngine.setVideoEncoderConfiguration(config); + result.success(null); + } + break; + case "removeNativeView": { + int viewId = call.argument("viewId"); + removeView(viewId); + result.success(null); + } + break; + case "setupLocalVideo": { + int localViewId = call.argument("viewId"); + SurfaceView localView = getView(localViewId); + int localRenderMode = call.argument("renderMode"); + VideoCanvas localCanvas = new VideoCanvas(localView); + localCanvas.renderMode = localRenderMode; + mRtcEngine.setupLocalVideo(localCanvas); + result.success(null); + } + break; + case "setupRemoteVideo": { + int remoteViewId = call.argument("viewId"); + SurfaceView view = getView(remoteViewId); + int remoteRenderMode = call.argument("renderMode"); + int remoteUid = call.argument("uid"); + mRtcEngine.setupRemoteVideo(new VideoCanvas(view , remoteRenderMode , remoteUid)); + result.success(null); + } + break; + case "setLocalRenderMode": { + int mode = call.argument("mode"); + mRtcEngine.setLocalRenderMode(mode); + result.success(null); + } + break; + case "setRemoteRenderMode": { + int uid = call.argument("uid"); + int mode = call.argument("mode"); + mRtcEngine.setRemoteRenderMode(uid , mode); + result.success(null); + } + break; + case "startPreview": { + mRtcEngine.startPreview(); + result.success(null); + } + break; + case "stopPreview": { + mRtcEngine.stopPreview(); + result.success(null); + } + break; + case "enableLocalVideo": { + boolean enabled = call.argument("enabled"); + mRtcEngine.enableLocalVideo(enabled); + result.success(null); + } + break; + case "muteLocalVideoStream": { + boolean muted = call.argument("muted"); + mRtcEngine.muteLocalVideoStream(muted); + result.success(null); + } + break; + case "muteRemoteVideoStream": { + int uid = call.argument("uid"); + boolean muted = call.argument("muted"); + mRtcEngine.muteRemoteVideoStream(uid , muted); + result.success(null); + } + break; + case "muteAllRemoteVideoStreams": { + boolean muted = call.argument("muted"); + mRtcEngine.muteAllRemoteVideoStreams(muted); + result.success(null); + } + break; + case "setDefaultMuteAllRemoteVideoStreams": { + boolean muted = call.argument("muted"); + mRtcEngine.setDefaultMuteAllRemoteVideoStreams(muted); + result.success(null); + } + break; + + // Audio Routing Controller + case "setDefaultAudioRouteToSpeaker": { + boolean defaultToSpeaker = call.argument("defaultToSpeaker"); + mRtcEngine.setDefaultAudioRoutetoSpeakerphone(defaultToSpeaker); + result.success(null); + } + break; + case "setEnableSpeakerphone": { + boolean enabled = call.argument("enabled"); + mRtcEngine.setEnableSpeakerphone(enabled); + result.success(null); + } + break; + case "isSpeakerphoneEnabled": { + boolean enabled = mRtcEngine.isSpeakerphoneEnabled(); + result.success(enabled); + } + break; + + // Stream Fallback + case "setRemoteUserPriority": { + int uid = call.argument("uid"); + int userPriority = call.argument("userPriority"); + mRtcEngine.setRemoteUserPriority(uid , userPriority); + result.success(null); + } + case "setLocalPublishFallbackOption": { + int option = call.argument("option"); + mRtcEngine.setLocalPublishFallbackOption(option); + result.success(null); + } + break; + case "setRemoteSubscribeFallbackOption": { + int option = call.argument("option"); + mRtcEngine.setRemoteSubscribeFallbackOption(option); + result.success(null); + } + break; + + // Dual-stream Mode + case "enableDualStreamMode": { + boolean enabled = call.argument("enabled"); + mRtcEngine.enableDualStreamMode(enabled); + result.success(null); + } + break; + case "setRemoteVideoStreamType": { + int uid = call.argument("uid"); + int streamType = call.argument("streamType"); + mRtcEngine.setRemoteVideoStreamType(uid , streamType); + result.success(null); + } + break; + case "setRemoteDefaultVideoStreamType": { + int streamType = call.argument("streamType"); + mRtcEngine.setRemoteDefaultVideoStreamType(streamType); + result.success(null); + } + break; + + // Encryption + case "setEncryptionSecret": { + String secret = call.argument("secret"); + mRtcEngine.setEncryptionSecret(secret); + result.success(null); + } + break; + case "setEncryptionMode": { + String encryptionMode = call.argument("encryptionMode"); + mRtcEngine.setEncryptionMode(encryptionMode); + result.success(null); + } + break; + + // Camera Control + case "switchCamera": { + mRtcEngine.switchCamera(); + result.success(null); + } + break; + + // Miscellaneous Methods + case "getSdkVersion": { + String version = RtcEngine.getSdkVersion(); + result.success(version); + } + break; + + default: + result.notImplemented(); + } } - @Override - public void onConnectionLost() { - super.onConnectionLost(); - invokeMethod("onConnectionLost", null); + private VideoEncoderConfiguration.ORIENTATION_MODE orientationFromValue(int value) { + switch (value) { + case 0: + return VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE; + case 1: + return VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_LANDSCAPE; + case 2: + return VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT; + default: + return VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE; + } } - @Override - public void onNetworkTypeChanged (int type) { - super.onNetworkTypeChanged(type); - HashMap map = new HashMap<>(); - map.put("type", type); - invokeMethod("onNetworkTypeChanged", map); - } + private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() { + @Override + public void onWarning(int warn) { + super.onWarning(warn); + HashMap map = new HashMap<>(); + map.put("warn" , warn); + invokeMethod("onWarning" , map); + } - @Override - public void onApiCallExecuted(int error, String api, String result) { - super.onApiCallExecuted(error, api, result); - HashMap map = new HashMap<>(); - map.put("error", error); - map.put("api", api); - map.put("result", result); - invokeMethod("onApiCallExecuted", map); - } + @Override + public void onError(int err) { + super.onError(err); + HashMap map = new HashMap<>(); + map.put("err" , err); + invokeMethod("onError" , map); + } - @Override - public void onTokenPrivilegeWillExpire(String token) { - super.onTokenPrivilegeWillExpire(token); - HashMap map = new HashMap<>(); - map.put("token", token); - invokeMethod("onTokenPrivilegeWillExpire", map); - } + @Override + public void onJoinChannelSuccess(String channel , int uid , int elapsed) { + super.onJoinChannelSuccess(channel , uid , elapsed); + HashMap map = new HashMap<>(); + map.put("channel" , channel); + map.put("uid" , uid); + map.put("elapsed" , elapsed); + invokeMethod("onJoinChannelSuccess" , map); + } - @Override - public void onRequestToken() { - super.onRequestToken(); - invokeMethod("onRequestToken", null); - } + @Override + public void onRejoinChannelSuccess(String channel , int uid , int elapsed) { + super.onRejoinChannelSuccess(channel , uid , elapsed); + HashMap map = new HashMap<>(); + map.put("channel" , channel); + map.put("uid" , uid); + map.put("elapsed" , elapsed); + invokeMethod("onRejoinChannelSuccess" , map); + } - @Override - public void onMicrophoneEnabled(boolean enabled) { - super.onMicrophoneEnabled(enabled); - HashMap map = new HashMap<>(); - map.put("enabled", enabled); - invokeMethod("onMicrophoneEnabled", map); - } + @Override + public void onLeaveChannel(RtcStats stats) { + super.onLeaveChannel(stats); + HashMap map = new HashMap<>(); + map.put("stats" , mapFromStats(stats)); + invokeMethod("onLeaveChannel" , map); + } - @Override - public void onAudioVolumeIndication(AudioVolumeInfo[] speakers, int totalVolume) { - super.onAudioVolumeIndication(speakers, totalVolume); - HashMap map = new HashMap<>(); - map.put("totalVolume", totalVolume); - map.put("speakers", arrayFromSpeakers(speakers)); - invokeMethod("onAudioVolumeIndication", map); - } + @Override + public void onClientRoleChanged(int oldRole , int newRole) { + super.onClientRoleChanged(oldRole , newRole); + HashMap map = new HashMap<>(); + map.put("oldRole" , oldRole); + map.put("newRole" , newRole); + invokeMethod("onClientRoleChanged" , map); + } - @Override - public void onActiveSpeaker(int uid) { - super.onActiveSpeaker(uid); - HashMap map = new HashMap<>(); - map.put("uid", uid); - invokeMethod("onActiveSpeaker", map); - } + @Override + public void onUserJoined(int uid , int elapsed) { + super.onUserJoined(uid , elapsed); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("elapsed" , elapsed); + invokeMethod("onUserJoined" , map); + } - @Override - public void onFirstLocalAudioFrame(int elapsed) { - super.onFirstLocalAudioFrame(elapsed); - HashMap map = new HashMap<>(); - map.put("elapsed", elapsed); - invokeMethod("onFirstLocalAudioFrame", map); - } + @Override + public void onUserOffline(int uid , int reason) { + super.onUserOffline(uid , reason); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("reason" , reason); + invokeMethod("onUserOffline" , map); + } - @Override - public void onFirstRemoteAudioFrame(int uid, int elapsed) { - super.onFirstRemoteAudioFrame(uid, elapsed); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("elapsed", elapsed); - invokeMethod("onFirstRemoteAudioFrame", map); - } + @Override + public void onConnectionStateChanged(int state , int reason) { + super.onConnectionStateChanged(state , reason); + HashMap map = new HashMap<>(); + map.put("state" , state); + map.put("reason" , reason); + invokeMethod("onConnectionStateChanged" , map); + } - @Override - public void onFirstRemoteAudioDecoded(int uid, int elapsed) { - super.onFirstRemoteAudioDecoded(uid, elapsed); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("elapsed", elapsed); - invokeMethod("onFirstRemoteAudioDecoded", map); - } + @Override + public void onConnectionLost() { + super.onConnectionLost(); + invokeMethod("onConnectionLost" , null); + } - @Override - public void onFirstLocalVideoFrame(int width, int height, int elapsed) { - super.onFirstLocalVideoFrame(width, height, elapsed); - HashMap map = new HashMap<>(); - map.put("width", width); - map.put("height", height); - map.put("elapsed", elapsed); - invokeMethod("onFirstLocalVideoFrame", map); - } + @Override + public void onNetworkTypeChanged(int type) { + super.onNetworkTypeChanged(type); + HashMap map = new HashMap<>(); + map.put("type" , type); + invokeMethod("onNetworkTypeChanged" , map); + } - @Override - public void onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed) { - super.onFirstRemoteVideoDecoded(uid, width, height, elapsed); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("width", width); - map.put("height", height); - map.put("elapsed", elapsed); - invokeMethod("onFirstRemoteVideoDecoded", map); - } + @Override + public void onApiCallExecuted(int error , String api , String result) { + super.onApiCallExecuted(error , api , result); + HashMap map = new HashMap<>(); + map.put("error" , error); + map.put("api" , api); + map.put("result" , result); + invokeMethod("onApiCallExecuted" , map); + } - @Override - public void onFirstRemoteVideoFrame(int uid, int width, int height, int elapsed) { - super.onFirstRemoteVideoFrame(uid, width, height, elapsed); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("width", width); - map.put("height", height); - map.put("elapsed", elapsed); - invokeMethod("onFirstRemoteVideoFrame", map); - } + @Override + public void onTokenPrivilegeWillExpire(String token) { + super.onTokenPrivilegeWillExpire(token); + HashMap map = new HashMap<>(); + map.put("token" , token); + invokeMethod("onTokenPrivilegeWillExpire" , map); + } - @Override - public void onUserMuteAudio(int uid, boolean muted) { - super.onUserMuteAudio(uid, muted); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("muted", muted); - invokeMethod("onUserMuteAudio", map); - } + @Override + public void onRequestToken() { + super.onRequestToken(); + invokeMethod("onRequestToken" , null); + } - @Override - public void onUserMuteVideo(int uid, boolean muted) { - super.onUserMuteVideo(uid, muted); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("muted", muted); - invokeMethod("onUserMuteVideo", map); - } + @Override + public void onMicrophoneEnabled(boolean enabled) { + super.onMicrophoneEnabled(enabled); + HashMap map = new HashMap<>(); + map.put("enabled" , enabled); + invokeMethod("onMicrophoneEnabled" , map); + } - @Override - public void onUserEnableVideo(int uid, boolean enabled) { - super.onUserEnableVideo(uid, enabled); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("enabled", enabled); - invokeMethod("onUserEnableVideo", map); - } + @Override + public void onAudioVolumeIndication(AudioVolumeInfo[] speakers , int totalVolume) { + super.onAudioVolumeIndication(speakers , totalVolume); + HashMap map = new HashMap<>(); + map.put("totalVolume" , totalVolume); + map.put("speakers" , arrayFromSpeakers(speakers)); + invokeMethod("onAudioVolumeIndication" , map); + } - @Override - public void onUserEnableLocalVideo(int uid, boolean enabled) { - super.onUserEnableLocalVideo(uid, enabled); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("enabled", enabled); - invokeMethod("onUserEnableLocalVideo", map); - } + @Override + public void onActiveSpeaker(int uid) { + super.onActiveSpeaker(uid); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + invokeMethod("onActiveSpeaker" , map); + } - @Override - public void onVideoSizeChanged(int uid, int width, int height, int rotation) { - super.onVideoSizeChanged(uid, width, height, rotation); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("width", width); - map.put("height", height); - map.put("rotation", rotation); - invokeMethod("onVideoSizeChanged", map); - } + @Override + public void onFirstLocalAudioFrame(int elapsed) { + super.onFirstLocalAudioFrame(elapsed); + HashMap map = new HashMap<>(); + map.put("elapsed" , elapsed); + invokeMethod("onFirstLocalAudioFrame" , map); + } - @Override - public void onRemoteVideoStateChanged(int uid, int state) { - super.onRemoteVideoStateChanged(uid, state); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("state", state); - invokeMethod("onRemoteVideoStateChanged", map); - } + @Override + public void onFirstRemoteAudioFrame(int uid , int elapsed) { + super.onFirstRemoteAudioFrame(uid , elapsed); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("elapsed" , elapsed); + invokeMethod("onFirstRemoteAudioFrame" , map); + } - @Override - public void onLocalPublishFallbackToAudioOnly(boolean isFallbackOrRecover) { - super.onLocalPublishFallbackToAudioOnly(isFallbackOrRecover); - HashMap map = new HashMap<>(); - map.put("isFallbackOrRecover", isFallbackOrRecover); - invokeMethod("onLocalPublishFallbackToAudioOnly", map); - } + @Override + public void onFirstRemoteAudioDecoded(int uid , int elapsed) { + super.onFirstRemoteAudioDecoded(uid , elapsed); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("elapsed" , elapsed); + invokeMethod("onFirstRemoteAudioDecoded" , map); + } - @Override - public void onRemoteSubscribeFallbackToAudioOnly(int uid, boolean isFallbackOrRecover) { - super.onRemoteSubscribeFallbackToAudioOnly(uid, isFallbackOrRecover); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("isFallbackOrRecover", isFallbackOrRecover); - invokeMethod("onRemoteSubscribeFallbackToAudioOnly", map); - } + @Override + public void onFirstLocalVideoFrame(int width , int height , int elapsed) { + super.onFirstLocalVideoFrame(width , height , elapsed); + HashMap map = new HashMap<>(); + map.put("width" , width); + map.put("height" , height); + map.put("elapsed" , elapsed); + invokeMethod("onFirstLocalVideoFrame" , map); + } - @Override - public void onAudioRouteChanged(int routing) { - super.onAudioRouteChanged(routing); - HashMap map = new HashMap<>(); - map.put("routing", routing); - invokeMethod("onAudioRouteChanged", map); - } + @Override + public void onFirstRemoteVideoDecoded(int uid , int width , int height , int elapsed) { + super.onFirstRemoteVideoDecoded(uid , width , height , elapsed); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("width" , width); + map.put("height" , height); + map.put("elapsed" , elapsed); + invokeMethod("onFirstRemoteVideoDecoded" , map); + } - @Override - public void onCameraFocusAreaChanged(Rect rect) { - super.onCameraFocusAreaChanged(rect); - HashMap map = new HashMap<>(); - map.put("rect", mapFromRect(rect)); - invokeMethod("onCameraFocusAreaChanged", map); - } + @Override + public void onFirstRemoteVideoFrame(int uid , int width , int height , int elapsed) { + super.onFirstRemoteVideoFrame(uid , width , height , elapsed); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("width" , width); + map.put("height" , height); + map.put("elapsed" , elapsed); + invokeMethod("onFirstRemoteVideoFrame" , map); + } - @Override - public void onCameraExposureAreaChanged(Rect rect) { - super.onCameraExposureAreaChanged(rect); - HashMap map = new HashMap<>(); - map.put("rect", mapFromRect(rect)); - invokeMethod("onCameraExposureAreaChanged", map); - } + @Override + public void onUserMuteAudio(int uid , boolean muted) { + super.onUserMuteAudio(uid , muted); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("muted" , muted); + invokeMethod("onUserMuteAudio" , map); + } - @Override - public void onRtcStats(RtcStats stats) { - super.onRtcStats(stats); - HashMap map = new HashMap<>(); - map.put("stats", mapFromStats(stats)); - invokeMethod("onRtcStats", map); - } + @Override + public void onUserMuteVideo(int uid , boolean muted) { + super.onUserMuteVideo(uid , muted); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("muted" , muted); + invokeMethod("onUserMuteVideo" , map); + } - @Override - public void onLastmileQuality(int quality) { - super.onLastmileQuality(quality); - HashMap map = new HashMap<>(); - map.put("quality", quality); - invokeMethod("onLastmileQuality", map); - } + @Override + public void onUserEnableVideo(int uid , boolean enabled) { + super.onUserEnableVideo(uid , enabled); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("enabled" , enabled); + invokeMethod("onUserEnableVideo" , map); + } - @Override - public void onNetworkQuality(int uid, int txQuality, int rxQuality) { - super.onNetworkQuality(uid, txQuality, rxQuality); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("txQuality", txQuality); - map.put("rxQuality", rxQuality); - invokeMethod("onNetworkQuality", map); - } + @Override + public void onUserEnableLocalVideo(int uid , boolean enabled) { + super.onUserEnableLocalVideo(uid , enabled); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("enabled" , enabled); + invokeMethod("onUserEnableLocalVideo" , map); + } - @Override - public void onLocalVideoStats(LocalVideoStats stats) { - super.onLocalVideoStats(stats); - HashMap map = new HashMap<>(); - map.put("stats", mapFromLocalVideoStats(stats)); - invokeMethod("onLocalVideoStats", map); - } + @Override + public void onVideoSizeChanged(int uid , int width , int height , int rotation) { + super.onVideoSizeChanged(uid , width , height , rotation); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("width" , width); + map.put("height" , height); + map.put("rotation" , rotation); + invokeMethod("onVideoSizeChanged" , map); + } - @Override - public void onRemoteVideoStats(RemoteVideoStats stats) { - super.onRemoteVideoStats(stats); - HashMap map = new HashMap<>(); - map.put("stats", mapFromRemoteVideoStats(stats)); - invokeMethod("onRemoteVideoStats", map); - } + @Override + public void onRemoteVideoStateChanged(int uid , int state) { + super.onRemoteVideoStateChanged(uid , state); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("state" , state); + invokeMethod("onRemoteVideoStateChanged" , map); + } - @Override - public void onRemoteAudioStats(RemoteAudioStats stats) { - super.onRemoteAudioStats(stats); - HashMap map = new HashMap<>(); - map.put("stats", mapFromRemoteAudioStats(stats)); - invokeMethod("onRemoteAudioStats", map); - } + @Override + public void onLocalPublishFallbackToAudioOnly(boolean isFallbackOrRecover) { + super.onLocalPublishFallbackToAudioOnly(isFallbackOrRecover); + HashMap map = new HashMap<>(); + map.put("isFallbackOrRecover" , isFallbackOrRecover); + invokeMethod("onLocalPublishFallbackToAudioOnly" , map); + } - @Override - public void onRemoteAudioTransportStats(int uid, int delay, int lost, int rxKBitRate) { - super.onRemoteAudioTransportStats(uid, delay, lost, rxKBitRate); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("delay", delay); - map.put("lost", lost); - map.put("rxKBitRate", rxKBitRate); - invokeMethod("onRemoteAudioTransportStats", map); - } + @Override + public void onRemoteSubscribeFallbackToAudioOnly(int uid , boolean isFallbackOrRecover) { + super.onRemoteSubscribeFallbackToAudioOnly(uid , isFallbackOrRecover); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("isFallbackOrRecover" , isFallbackOrRecover); + invokeMethod("onRemoteSubscribeFallbackToAudioOnly" , map); + } - @Override - public void onRemoteVideoTransportStats(int uid, int delay, int lost, int rxKBitRate) { - super.onRemoteVideoTransportStats(uid, delay, lost, rxKBitRate); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("delay", delay); - map.put("lost", lost); - map.put("rxKBitRate", rxKBitRate); - invokeMethod("onRemoteVideoTransportStats", map); - } + @Override + public void onAudioRouteChanged(int routing) { + super.onAudioRouteChanged(routing); + HashMap map = new HashMap<>(); + map.put("routing" , routing); + invokeMethod("onAudioRouteChanged" , map); + } - @Override - public void onLocalVideoStateChanged(int localVideoState, int error) { - super.onLocalVideoStateChanged(localVideoState, error); - HashMap map = new HashMap<>(); - map.put("localVideoState", localVideoState); - map.put("error", error); - invokeMethod("onLocalVideoStateChanged", map); - } + @Override + public void onCameraFocusAreaChanged(Rect rect) { + super.onCameraFocusAreaChanged(rect); + HashMap map = new HashMap<>(); + map.put("rect" , mapFromRect(rect)); + invokeMethod("onCameraFocusAreaChanged" , map); + } - @Override - public void onAudioEffectFinished(int soundId) { - super.onAudioEffectFinished(soundId); - HashMap map = new HashMap<>(); - map.put("soundId", soundId); - invokeMethod("onAudioEffectFinished", map); - } + @Override + public void onCameraExposureAreaChanged(Rect rect) { + super.onCameraExposureAreaChanged(rect); + HashMap map = new HashMap<>(); + map.put("rect" , mapFromRect(rect)); + invokeMethod("onCameraExposureAreaChanged" , map); + } - @Override - public void onStreamPublished(String url, int error) { - super.onStreamPublished(url, error); - HashMap map = new HashMap<>(); - map.put("url", url); - map.put("error", error); - invokeMethod("onStreamPublished", map); - } + @Override + public void onRtcStats(RtcStats stats) { + super.onRtcStats(stats); + HashMap map = new HashMap<>(); + map.put("stats" , mapFromStats(stats)); + invokeMethod("onRtcStats" , map); + } - @Override - public void onStreamUnpublished(String url) { - super.onStreamUnpublished(url); - HashMap map = new HashMap<>(); - map.put("url", url); - invokeMethod("onStreamUnpublished", map); - } + @Override + public void onLastmileQuality(int quality) { + super.onLastmileQuality(quality); + HashMap map = new HashMap<>(); + map.put("quality" , quality); + invokeMethod("onLastmileQuality" , map); + } - @Override - public void onTranscodingUpdated() { - super.onTranscodingUpdated(); - invokeMethod("onTranscodingUpdated", null); - } + @Override + public void onNetworkQuality(int uid , int txQuality , int rxQuality) { + super.onNetworkQuality(uid , txQuality , rxQuality); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("txQuality" , txQuality); + map.put("rxQuality" , rxQuality); + invokeMethod("onNetworkQuality" , map); + } - @Override - public void onStreamInjectedStatus(String url, int uid, int status) { - super.onStreamInjectedStatus(url, uid, status); - HashMap map = new HashMap<>(); - map.put("url", url); - map.put("uid", uid); - map.put("status", status); - invokeMethod("onStreamInjectedStatus", map); - } + @Override + public void onLocalVideoStats(LocalVideoStats stats) { + super.onLocalVideoStats(stats); + HashMap map = new HashMap<>(); + map.put("stats" , mapFromLocalVideoStats(stats)); + invokeMethod("onLocalVideoStats" , map); + } - @Override - public void onStreamMessage(int uid, int streamId, byte[] data) { - super.onStreamMessage(uid, streamId, data); - try { - String message = new String(data, "UTF-8"); - HashMap map = new HashMap<>(); - map.put("streamId", streamId); - map.put("uid", uid); - map.put("message", message); - invokeMethod("onStreamMessage", map); - } catch (Exception e) { - e.printStackTrace(); - } - } + @Override + public void onRemoteVideoStats(RemoteVideoStats stats) { + super.onRemoteVideoStats(stats); + HashMap map = new HashMap<>(); + map.put("stats" , mapFromRemoteVideoStats(stats)); + invokeMethod("onRemoteVideoStats" , map); + } - @Override - public void onStreamMessageError(int uid, int streamId, int error, int missed, int cached) { - super.onStreamMessageError(uid, streamId, error, missed, cached); - HashMap map = new HashMap<>(); - map.put("uid", uid); - map.put("streamId", streamId); - map.put("error", error); - map.put("missed", missed); - map.put("cached", cached); - invokeMethod("onStreamMessageError", map); - } + @Override + public void onRemoteAudioStats(RemoteAudioStats stats) { + super.onRemoteAudioStats(stats); + HashMap map = new HashMap<>(); + map.put("stats" , mapFromRemoteAudioStats(stats)); + invokeMethod("onRemoteAudioStats" , map); + } - @Override - public void onMediaEngineLoadSuccess() { - super.onMediaEngineLoadSuccess(); - invokeMethod("onMediaEngineLoadSuccess", null); - } + @Override + public void onRemoteAudioTransportStats(int uid , int delay , int lost , int rxKBitRate) { + super.onRemoteAudioTransportStats(uid , delay , lost , rxKBitRate); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("delay" , delay); + map.put("lost" , lost); + map.put("rxKBitRate" , rxKBitRate); + invokeMethod("onRemoteAudioTransportStats" , map); + } - @Override - public void onMediaEngineStartCallSuccess() { - super.onMediaEngineStartCallSuccess(); - invokeMethod("onMediaEngineStartCallSuccess", null); - } + @Override + public void onRemoteVideoTransportStats(int uid , int delay , int lost , int rxKBitRate) { + super.onRemoteVideoTransportStats(uid , delay , lost , rxKBitRate); + HashMap map = new HashMap<>(); + map.put("uid" , uid); + map.put("delay" , delay); + map.put("lost" , lost); + map.put("rxKBitRate" , rxKBitRate); + invokeMethod("onRemoteVideoTransportStats" , map); + } - private HashMap mapFromStats(RtcStats stats) { - HashMap map = new HashMap<>(); - map.put("duration", stats.totalDuration); - map.put("txBytes", stats.txBytes); - map.put("rxBytes", stats.rxBytes); - map.put("txAudioKBitrate", stats.txAudioKBitRate); - map.put("rxAudioKBitrate", stats.rxAudioKBitRate); - map.put("txVideoKBitrate", stats.txVideoKBitRate); - map.put("rxVideoKBitrate", stats.rxVideoKBitRate); - map.put("txPacketLossRate", stats.txPacketLossRate); - map.put("rxPacketLossRate", stats.rxPacketLossRate); - map.put("lastmileDelay", stats.lastmileDelay); - map.put("userCount", stats.users); - map.put("cpuAppUsage", stats.cpuAppUsage); - map.put("cpuTotalUsage", stats.cpuTotalUsage); - return map; - } + @Override + public void onLocalVideoStateChanged(int localVideoState , int error) { + super.onLocalVideoStateChanged(localVideoState , error); + HashMap map = new HashMap<>(); + map.put("localVideoState" , localVideoState); + map.put("error" , error); + invokeMethod("onLocalVideoStateChanged" , map); + } - private HashMap mapFromRect(Rect rect) { - HashMap map = new HashMap<>(); + @Override + public void onAudioEffectFinished(int soundId) { + super.onAudioEffectFinished(soundId); + HashMap map = new HashMap<>(); + map.put("soundId" , soundId); + invokeMethod("onAudioEffectFinished" , map); + } - map.put("x", rect.left); - map.put("y", rect.top); - map.put("width", rect.width()); - map.put("height", rect.height()); - return map; - } + @Override + public void onStreamPublished(String url , int error) { + super.onStreamPublished(url , error); + HashMap map = new HashMap<>(); + map.put("url" , url); + map.put("error" , error); + invokeMethod("onStreamPublished" , map); + } - private HashMap mapFromLocalVideoStats(LocalVideoStats stats) { - HashMap map = new HashMap<>(); - map.put("sentBitrate", stats.sentBitrate); - map.put("sentFrameRate", stats.sentFrameRate); - map.put("encoderOutputFrameRate", stats.encoderOutputFrameRate); - map.put("rendererOutputFrameRate", stats.rendererOutputFrameRate); - return map; - } + @Override + public void onStreamUnpublished(String url) { + super.onStreamUnpublished(url); + HashMap map = new HashMap<>(); + map.put("url" , url); + invokeMethod("onStreamUnpublished" , map); + } - private HashMap mapFromRemoteVideoStats(RemoteVideoStats stats) { - HashMap map = new HashMap<>(); - map.put("uid", stats.uid); - map.put("width", stats.width); - map.put("height", stats.height); - map.put("receivedBitrate", stats.receivedBitrate); - map.put("decoderOutputFrameRate", stats.decoderOutputFrameRate); - map.put("rendererOutputFrameRate", stats.rendererOutputFrameRate); - map.put("rxStreamType", stats.rxStreamType); - return map; - } + @Override + public void onTranscodingUpdated() { + super.onTranscodingUpdated(); + invokeMethod("onTranscodingUpdated" , null); + } - private HashMap mapFromRemoteAudioStats(RemoteAudioStats stats) { - HashMap map = new HashMap<>(); - map.put("uid", stats.uid); - map.put("quality", stats.quality); - map.put("networkTransportDelay", stats.networkTransportDelay); - map.put("jitterBufferDelay", stats.jitterBufferDelay); - map.put("audioLossRate", stats.audioLossRate); - return map; - } + @Override + public void onStreamInjectedStatus(String url , int uid , int status) { + super.onStreamInjectedStatus(url , uid , status); + HashMap map = new HashMap<>(); + map.put("url" , url); + map.put("uid" , uid); + map.put("status" , status); + invokeMethod("onStreamInjectedStatus" , map); + } - private ArrayList> arrayFromSpeakers(AudioVolumeInfo[] speakers) { - ArrayList> list = new ArrayList<>(); + @Override + public void onStreamMessage(int uid , int streamId , byte[] data) { + super.onStreamMessage(uid , streamId , data); + try { + String message = new String(data , "UTF-8"); + HashMap map = new HashMap<>(); + map.put("streamId" , streamId); + map.put("uid" , uid); + map.put("message" , message); + invokeMethod("onStreamMessage" , map); + } catch (Exception e) { + e.printStackTrace(); + } + } - for (AudioVolumeInfo info: speakers) { + @Override + public void onStreamMessageError(int uid , int streamId , int error , int missed , + int cached) { + super.onStreamMessageError(uid , streamId , error , missed , cached); HashMap map = new HashMap<>(); - map.put("uid", info.uid); - map.put("volume", info.volume); + map.put("uid" , uid); + map.put("streamId" , streamId); + map.put("error" , error); + map.put("missed" , missed); + map.put("cached" , cached); + invokeMethod("onStreamMessageError" , map); + } - list.add(map); + @Override + public void onMediaEngineLoadSuccess() { + super.onMediaEngineLoadSuccess(); + invokeMethod("onMediaEngineLoadSuccess" , null); } - return list; - } - }; - - private BeautyOptions beautyOptionsFromMap(HashMap map) { - BeautyOptions options = new BeautyOptions(); - options.lighteningContrastLevel = ((Double)(map.get("lighteningContrastLevel"))).intValue(); - options.lighteningLevel = ((Double)(map.get("lighteningLevel"))).floatValue(); - options.smoothnessLevel = ((Double)(map.get("smoothnessLevel"))).floatValue(); - options.rednessLevel = ((Double)(map.get("rednessLevel"))).floatValue(); - return options; - } - - private VideoEncoderConfiguration videoEncoderConfigurationFromMap(HashMap map) { - int width = (int)(map.get("width")); - int height = (int)(map.get("height")); - int frameRate = (int)(map.get("frameRate")); - int bitrate = (int)(map.get("bitrate")); - int minBitrate = (int)(map.get("minBitrate")); - int orientationMode = (int)(map.get("orientationMode")); - - VideoEncoderConfiguration configuration = new VideoEncoderConfiguration(); - configuration.dimensions = new VideoEncoderConfiguration.VideoDimensions(width, height); - configuration.frameRate = frameRate; - configuration.bitrate = bitrate; - configuration.minBitrate = minBitrate; - configuration.orientationMode = orientationFromValue(orientationMode); - - return configuration; - } - - private void invokeMethod(final String method, final HashMap map) { - mEventHandler.post(new Runnable() { - @Override - public void run() { - mMethodChannel.invokeMethod(method, map); - } - }); - } - - private static class MethodResultWrapper implements MethodChannel.Result { - private MethodChannel.Result mResult; - private Handler mHandler; - - MethodResultWrapper(MethodChannel.Result result, Handler handler) { - this.mResult = result; - this.mHandler = handler; - } + @Override + public void onMediaEngineStartCallSuccess() { + super.onMediaEngineStartCallSuccess(); + invokeMethod("onMediaEngineStartCallSuccess" , null); + } + + private HashMap mapFromStats(RtcStats stats) { + HashMap map = new HashMap<>(); + map.put("duration" , stats.totalDuration); + map.put("txBytes" , stats.txBytes); + map.put("rxBytes" , stats.rxBytes); + map.put("txAudioKBitrate" , stats.txAudioKBitRate); + map.put("rxAudioKBitrate" , stats.rxAudioKBitRate); + map.put("txVideoKBitrate" , stats.txVideoKBitRate); + map.put("rxVideoKBitrate" , stats.rxVideoKBitRate); + map.put("txPacketLossRate" , stats.txPacketLossRate); + map.put("rxPacketLossRate" , stats.rxPacketLossRate); + map.put("lastmileDelay" , stats.lastmileDelay); + map.put("userCount" , stats.users); + map.put("cpuAppUsage" , stats.cpuAppUsage); + map.put("cpuTotalUsage" , stats.cpuTotalUsage); + return map; + } + + private HashMap mapFromRect(Rect rect) { + HashMap map = new HashMap<>(); + + map.put("x" , rect.left); + map.put("y" , rect.top); + map.put("width" , rect.width()); + map.put("height" , rect.height()); + return map; + } + + private HashMap mapFromLocalVideoStats(LocalVideoStats stats) { + HashMap map = new HashMap<>(); + map.put("sentBitrate" , stats.sentBitrate); + map.put("sentFrameRate" , stats.sentFrameRate); + map.put("encoderOutputFrameRate" , stats.encoderOutputFrameRate); + map.put("rendererOutputFrameRate" , stats.rendererOutputFrameRate); + return map; + } + + private HashMap mapFromRemoteVideoStats(RemoteVideoStats stats) { + HashMap map = new HashMap<>(); + map.put("uid" , stats.uid); + map.put("width" , stats.width); + map.put("height" , stats.height); + map.put("receivedBitrate" , stats.receivedBitrate); + map.put("decoderOutputFrameRate" , stats.decoderOutputFrameRate); + map.put("rendererOutputFrameRate" , stats.rendererOutputFrameRate); + map.put("rxStreamType" , stats.rxStreamType); + return map; + } + + private HashMap mapFromRemoteAudioStats(RemoteAudioStats stats) { + HashMap map = new HashMap<>(); + map.put("uid" , stats.uid); + map.put("quality" , stats.quality); + map.put("networkTransportDelay" , stats.networkTransportDelay); + map.put("jitterBufferDelay" , stats.jitterBufferDelay); + map.put("audioLossRate" , stats.audioLossRate); + return map; + } + + private ArrayList> arrayFromSpeakers(AudioVolumeInfo[] speakers) { + ArrayList> list = new ArrayList<>(); + + for (AudioVolumeInfo info : speakers) { + HashMap map = new HashMap<>(); + map.put("uid" , info.uid); + map.put("volume" , info.volume); + + list.add(map); + } + + return list; + } + }; + + private BeautyOptions beautyOptionsFromMap(HashMap map) { + BeautyOptions options = new BeautyOptions(); + options.lighteningContrastLevel = + ((Double) (map.get("lighteningContrastLevel"))).intValue(); + options.lighteningLevel = ((Double) (map.get("lighteningLevel"))).floatValue(); + options.smoothnessLevel = ((Double) (map.get("smoothnessLevel"))).floatValue(); + options.rednessLevel = ((Double) (map.get("rednessLevel"))).floatValue(); + return options; + } + + private VideoEncoderConfiguration videoEncoderConfigurationFromMap(HashMap map) { + int width = (int) (map.get("width")); + int height = (int) (map.get("height")); + int frameRate = (int) (map.get("frameRate")); + int bitrate = (int) (map.get("bitrate")); + int minBitrate = (int) (map.get("minBitrate")); + int orientationMode = (int) (map.get("orientationMode")); + + VideoEncoderConfiguration configuration = new VideoEncoderConfiguration(); + configuration.dimensions = new VideoEncoderConfiguration.VideoDimensions(width , height); + configuration.frameRate = frameRate; + configuration.bitrate = bitrate; + configuration.minBitrate = minBitrate; + configuration.orientationMode = orientationFromValue(orientationMode); + + return configuration; + } + + private void invokeMethod(final String method , final HashMap map) { + mEventHandler.post(new Runnable() { + @Override + public void run() { + mMethodChannel.invokeMethod(method , map); + } + }); + } + + private static class MethodResultWrapper implements MethodChannel.Result { + private MethodChannel.Result mResult; + private Handler mHandler; + + MethodResultWrapper(MethodChannel.Result result , Handler handler) { + this.mResult = result; + this.mHandler = handler; + } - @Override - public void success(final Object result) { - mHandler.post(new Runnable() { @Override - public void run() { - mResult.success(result); + public void success(final Object result) { + mHandler.post(new Runnable() { + @Override + public void run() { + mResult.success(result); + } + }); } - }); - } - @Override - public void error(final String errorCode, final String errorMessage, final Object errorDetails) { - mHandler.post(new Runnable() { @Override - public void run() { - mResult.error(errorCode, errorMessage, errorDetails); + public void error(final String errorCode , final String errorMessage , + final Object errorDetails) { + mHandler.post(new Runnable() { + @Override + public void run() { + mResult.error(errorCode , errorMessage , errorDetails); + } + }); } - }); - } - @Override - public void notImplemented() { - mHandler.post(new Runnable() { @Override - public void run() { - mResult.notImplemented(); + public void notImplemented() { + mHandler.post(new Runnable() { + @Override + public void run() { + mResult.notImplemented(); + } + }); } - }); } - } } diff --git a/ios/Classes/AgoraRtcEnginePlugin.m b/ios/Classes/AgoraRtcEnginePlugin.m index bf4904e29..476ac32d7 100644 --- a/ios/Classes/AgoraRtcEnginePlugin.m +++ b/ios/Classes/AgoraRtcEnginePlugin.m @@ -95,15 +95,19 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([@"create" isEqualToString:method]) { NSString *appId = [self stringFromArguments:arguments key:@"appId"]; self.agoraRtcEngine = [AgoraRtcEngineKit sharedEngineWithAppId:appId delegate:self]; + result(nil); } else if ([@"destroy" isEqualToString:method]) { self.agoraRtcEngine = nil; [AgoraRtcEngineKit destroy]; + result(nil); } else if ([@"setChannelProfile" isEqualToString:method]) { NSInteger profile = [self intFromArguments:arguments key:@"profile"]; [self.agoraRtcEngine setChannelProfile:profile]; + result(nil); } else if ([@"setClientRole" isEqualToString:method]) { NSInteger role = [self intFromArguments:arguments key:@"role"]; [self.agoraRtcEngine setClientRole:role]; + result(nil); } else if ([@"joinChannel" isEqualToString:method]) { NSString *token = [self stringFromArguments:arguments key:@"token"]; NSString *channel = [self stringFromArguments:arguments key:@"channelId"]; @@ -111,80 +115,92 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSInteger uid = [self intFromArguments:arguments key:@"uid"]; [self.agoraRtcEngine joinChannelByToken:token channelId:channel info:info uid:uid joinSuccess:nil]; - if (result) { - result([NSNumber numberWithBool:YES]); - } + result([NSNumber numberWithBool:YES]); } else if ([@"leaveChannel" isEqualToString:method]) { BOOL success = (0 == [self.agoraRtcEngine leaveChannel:nil]); - if (result) { - result([NSNumber numberWithBool:success]); - } + result([NSNumber numberWithBool:success]); } else if ([@"renewToken" isEqualToString:method]) { NSString *token = [self stringFromArguments:arguments key:@"token"]; [self.agoraRtcEngine renewToken:token]; + result(nil); } else if ([@"enableWebSdkInteroperability" isEqualToString:method]) { BOOL enabled = [self boolFromArguments:arguments key:@"enabled"]; [self.agoraRtcEngine enableWebSdkInteroperability:enabled]; + result(nil); } else if ([@"getConnectionState" isEqualToString:method]) { AgoraConnectionStateType state = [self.agoraRtcEngine getConnectionState]; - if (result) { - result([NSNumber numberWithInteger:state]); - } + result([NSNumber numberWithInteger:state]); } // Core Audio else if ([@"enableAudio" isEqualToString:method]) { [self.agoraRtcEngine enableAudio]; + result(nil); } else if ([@"disableAudio" isEqualToString:method]) { [self.agoraRtcEngine disableAudio]; + result(nil); } else if ([@"setAudioProfile" isEqualToString:method]) { NSInteger profile = [self intFromArguments:arguments key:@"profile"]; NSInteger scenario = [self intFromArguments:arguments key:@"scenario"]; [self.agoraRtcEngine setAudioProfile:profile scenario:scenario]; + result(nil); } else if ([@"setAudioProfile" isEqualToString:method]) { NSInteger profile = [self intFromArguments:arguments key:@"profile"]; NSInteger scenario = [self intFromArguments:arguments key:@"scenario"]; [self.agoraRtcEngine setAudioProfile:profile scenario:scenario]; + result(nil); } else if ([@"adjustRecordingSignalVolume" isEqualToString:method]) { NSInteger volume = [self intFromArguments:arguments key:@"volume"]; [self.agoraRtcEngine adjustRecordingSignalVolume:volume]; + result(nil); } else if ([@"adjustPlaybackSignalVolume" isEqualToString:method]) { NSInteger volume = [self intFromArguments:arguments key:@"volume"]; [self.agoraRtcEngine adjustPlaybackSignalVolume:volume]; + result(nil); } else if ([@"enableAudioVolumeIndication" isEqualToString:method]) { NSInteger interval = [self intFromArguments:arguments key:@"interval"]; NSInteger smooth = [self intFromArguments:arguments key:@"smooth"]; [self.agoraRtcEngine enableAudioVolumeIndication:interval smooth:smooth]; + result(nil); } else if ([@"enableLocalAudio" isEqualToString:method]) { BOOL enabled = [self boolFromArguments:arguments key:@"enabled"]; [self.agoraRtcEngine enableLocalAudio:enabled]; + result(nil); } else if ([@"muteLocalAudioStream" isEqualToString:method]) { BOOL muted = [self boolFromArguments:arguments key:@"muted"]; [self.agoraRtcEngine muteLocalAudioStream:muted]; + result(nil); } else if ([@"muteRemoteAudioStream" isEqualToString:method]) { NSInteger uid = [self intFromArguments:arguments key:@"uid"]; BOOL muted = [self boolFromArguments:arguments key:@"muted"]; [self.agoraRtcEngine muteRemoteAudioStream:uid mute:muted]; + result(nil); } else if ([@"muteAllRemoteAudioStreams" isEqualToString:method]) { BOOL muted = [self boolFromArguments:arguments key:@"muted"]; [self.agoraRtcEngine muteAllRemoteAudioStreams:muted]; + result(nil); } else if ([@"setDefaultMuteAllRemoteAudioStreams" isEqualToString:method]) { BOOL muted = [self boolFromArguments:arguments key:@"muted"]; [self.agoraRtcEngine setDefaultMuteAllRemoteAudioStreams:muted]; + result(nil); } // Core Video else if ([@"enableVideo" isEqualToString:method]) { [self.agoraRtcEngine enableVideo]; + result(nil); } else if ([@"disableVideo" isEqualToString:method]) { [self.agoraRtcEngine disableVideo]; + result(nil); } else if ([@"setVideoEncoderConfiguration" isEqualToString:method]) { NSDictionary *configDic = [self dictionaryFromArguments:arguments key:@"config"]; AgoraVideoEncoderConfiguration *config = [self videoEncoderConfigurationFromDic:configDic]; [self.agoraRtcEngine setVideoEncoderConfiguration:config]; + result(nil); } else if ([@"removeNativeView" isEqualToString:method]) { NSString *viewId = [self stringFromArguments:arguments key:@"viewId"]; if (viewId.length) { [self.rendererViews removeObjectForKey:viewId]; } + result(nil); } else if ([@"setupLocalVideo" isEqualToString:method]) { NSInteger viewId = [self intFromArguments:arguments key:@"viewId"]; UIView *view = [AgoraRtcEnginePlugin viewForId:@(viewId)]; @@ -194,6 +210,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { canvas.view = view; canvas.renderMode = renderType; [self.agoraRtcEngine setupLocalVideo:canvas]; + result(nil); } else if ([@"setupRemoteVideo" isEqualToString:method]) { NSInteger viewId = [self intFromArguments:arguments key:@"viewId"]; UIView *view = [AgoraRtcEnginePlugin viewForId:@(viewId)]; @@ -205,33 +222,43 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { canvas.renderMode = renderType; canvas.uid = uid; [self.agoraRtcEngine setupRemoteVideo:canvas]; + result(nil); } else if ([@"setLocalRenderMode" isEqualToString:method]) { NSInteger mode = [self intFromArguments:arguments key:@"mode"]; [self.agoraRtcEngine setLocalRenderMode:mode]; + result(nil); } else if ([@"setRemoteRenderMode" isEqualToString:method]) { NSInteger uid = [self intFromArguments:arguments key:@"uid"]; NSInteger mode = [self intFromArguments:arguments key:@"mode"]; [self.agoraRtcEngine setRemoteRenderMode:uid mode:mode]; + result(nil); } else if ([@"startPreview" isEqualToString:method]) { [self.agoraRtcEngine startPreview]; + result(nil); } else if ([@"stopPreview" isEqualToString:method]) { [self.agoraRtcEngine stopPreview]; + result(nil); } else if ([@"enableLocalVideo" isEqualToString:method]) { BOOL enabled = [self boolFromArguments:arguments key:@"enabled"]; [self.agoraRtcEngine enableLocalVideo:enabled]; + result(nil); } else if ([@"muteLocalVideoStream" isEqualToString:method]) { BOOL muted = [self boolFromArguments:arguments key:@"muted"]; [self.agoraRtcEngine muteLocalVideoStream:muted]; + result(nil); } else if ([@"muteRemoteVideoStream" isEqualToString:method]) { NSInteger uid = [self intFromArguments:arguments key:@"uid"]; BOOL muted = [self boolFromArguments:arguments key:@"muted"]; [self.agoraRtcEngine muteRemoteVideoStream:uid mute:muted]; + result(nil); } else if ([@"muteAllRemoteVideoStreams" isEqualToString:method]) { BOOL muted = [self boolFromArguments:arguments key:@"muted"]; [self.agoraRtcEngine muteAllRemoteVideoStreams:muted]; + result(nil); } else if ([@"setDefaultMuteAllRemoteVideoStreams" isEqualToString:method]) { BOOL muted = [self boolFromArguments:arguments key:@"muted"]; [self.agoraRtcEngine setDefaultMuteAllRemoteVideoStreams:muted]; + result(nil); } // Video Pre-process and Post-process @@ -240,69 +267,75 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSDictionary *optionsDic = [self dictionaryFromArguments:arguments key:@"options"]; AgoraBeautyOptions *options = [self beautyOptionsFromDic:optionsDic]; [self.agoraRtcEngine setBeautyEffectOptions:enabled options:options]; + result(nil); } // Audio Routing Controller else if ([@"setDefaultAudioRouteToSpeaker" isEqualToString:method]) { BOOL defaultToSpeaker = [self boolFromArguments:arguments key:@"defaultToSpeaker"]; [self.agoraRtcEngine setDefaultAudioRouteToSpeakerphone:defaultToSpeaker]; + result(nil); } else if ([@"setEnableSpeakerphone" isEqualToString:method]) { BOOL enabled = [self boolFromArguments:arguments key:@"enabled"]; [self.agoraRtcEngine setEnableSpeakerphone:enabled]; + result(nil); } else if ([@"isSpeakerphoneEnabled" isEqualToString:method]) { BOOL enable = [self.agoraRtcEngine isSpeakerphoneEnabled]; - if (result) { - result([NSNumber numberWithBool:enable]); - } + result([NSNumber numberWithBool:enable]); } // Stream Fallback else if ([@"setRemoteUserPriority" isEqualToString:method]) { NSInteger uid = [self intFromArguments:arguments key:@"uid"]; AgoraUserPriority priority = [self intFromArguments:arguments key:@"userPriority"]; [self.agoraRtcEngine setRemoteUserPriority:uid type:priority]; + result(nil); } else if ([@"setLocalPublishFallbackOption" isEqualToString:method]) { NSInteger option = [self intFromArguments:arguments key:@"option"]; [self.agoraRtcEngine setLocalPublishFallbackOption:option]; + result(nil); } else if ([@"setRemoteSubscribeFallbackOption" isEqualToString:method]) { NSInteger option = [self intFromArguments:arguments key:@"option"]; [self.agoraRtcEngine setRemoteSubscribeFallbackOption:option]; + result(nil); } // Dual-stream Mode else if ([@"enableDualStreamMode" isEqualToString:method]) { BOOL enabled = [self boolFromArguments:arguments key:@"enabled"]; [self.agoraRtcEngine enableDualStreamMode:enabled]; + result(nil); } else if ([@"setRemoteVideoStreamType" isEqualToString:method]) { NSInteger uid = [self intFromArguments:arguments key:@"uid"]; NSInteger streamType = [self intFromArguments:arguments key:@"streamType"]; [self.agoraRtcEngine setRemoteVideoStream:uid type:streamType]; + result(nil); } else if ([@"setRemoteDefaultVideoStreamType" isEqualToString:method]) { NSInteger streamType = [self intFromArguments:arguments key:@"streamType"]; [self.agoraRtcEngine setRemoteDefaultVideoStreamType:streamType]; + result(nil); } // Encryption else if ([@"setEncryptionSecret" isEqualToString:method]) { NSString *secret = [self stringFromArguments:arguments key:@"secret"]; [self.agoraRtcEngine setEncryptionSecret:secret]; + result(nil); } else if ([@"setEncryptionMode" isEqualToString:method]) { NSString *encryptionMode = [self stringFromArguments:arguments key:@"encryptionMode"]; [self.agoraRtcEngine setEncryptionMode:encryptionMode]; + result(nil); } // Camera Control else if ([@"switchCamera" isEqualToString:method]) { [self.agoraRtcEngine switchCamera]; + result(nil); } // Miscellaneous Methods else if ([@"getSdkVersion" isEqualToString:method]) { NSString *version = [AgoraRtcEngineKit getSdkVersion]; - if (result) { - result(version); - } + result(version); } else { - if (result) { - result(FlutterMethodNotImplemented); - } + result(FlutterMethodNotImplemented); } }