فهرست منبع

finish call wrapper code

heavyrian2012 1 سال پیش
والد
کامیت
03ab399967

+ 2 - 0
.gitignore

@@ -2,3 +2,5 @@ build
 nativeplugins/wf-uni-wfc-client.zip
 nativeplugins/wf-uni-wfc-uikit.zip
 uni-iOS-SDK/HBuilder-uniPluginDemo/WFAVUniPlugin/WFAVUniPlugin.xcodeproj/xcuserdata
+uni-iOS-SDK/HBuilder-uniPluginDemo/WFPttClientUniPlugin/WFPttClientUniPlugin.xcodeproj/xcuserdata
+uni-iOS-SDK/HBuilder-uniPluginDemo/WFUIKitUniPlugin/WFUIKitUniPlugin.xcodeproj/xcuserdata

+ 23 - 0
uni-iOS-SDK/HBuilder-uniPluginDemo/HBuilder-Hello/HBuilder-uniPlugin-Info.plist

@@ -439,6 +439,29 @@
 	<true/>
 	<key>dcloud_uniplugins</key>
 	<array>
+		<dict>
+			<key>plugins</key>
+			<array>
+				<dict>
+					<key>type</key>
+					<string>component</string>
+					<key>name</key>
+					<string>UIKit-Video-CallView</string>
+					<key>class</key>
+					<string>WFAVRtcView</string>
+				</dict>
+				<dict>
+					<key>type</key>
+					<string>module</string>
+					<key>name</key>
+					<string>wf-uni-wfc-avclient</string>
+					<key>class</key>
+					<string>WFAVModule</string>
+				</dict>
+			</array>
+			<key>hooksClass</key>
+			<string>WFAVProxy</string>
+		</dict>
 		<dict>
 			<key>hooksClass</key>
 			<string>WFPttClientProxy</string>

+ 24 - 0
uni-iOS-SDK/HBuilder-uniPluginDemo/WFAVUniPlugin/WFAVUniPlugin.xcodeproj/project.pbxproj

@@ -9,12 +9,24 @@
 /* Begin PBXBuildFile section */
 		B72583772B0714E700C021C0 /* WebRTC.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = B72583762B0714E700C021C0 /* WebRTC.xcframework */; };
 		B725837B2B0714F300C021C0 /* WFAVEngineKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = B725837A2B0714F300C021C0 /* WFAVEngineKit.xcframework */; };
+		B72583802B07299500C021C0 /* WFAVModule.h in Headers */ = {isa = PBXBuildFile; fileRef = B725837E2B07299500C021C0 /* WFAVModule.h */; };
+		B72583812B07299500C021C0 /* WFAVModule.m in Sources */ = {isa = PBXBuildFile; fileRef = B725837F2B07299500C021C0 /* WFAVModule.m */; };
+		B72583842B0729C500C021C0 /* WFAVProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = B72583822B0729C500C021C0 /* WFAVProxy.h */; };
+		B72583852B0729C500C021C0 /* WFAVProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = B72583832B0729C500C021C0 /* WFAVProxy.m */; };
+		B72583882B072C5B00C021C0 /* WFAVRtcView.h in Headers */ = {isa = PBXBuildFile; fileRef = B72583862B072C5B00C021C0 /* WFAVRtcView.h */; };
+		B72583892B072C5B00C021C0 /* WFAVRtcView.m in Sources */ = {isa = PBXBuildFile; fileRef = B72583872B072C5B00C021C0 /* WFAVRtcView.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
 		B72583622B07139800C021C0 /* WFAVUniPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WFAVUniPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		B72583762B0714E700C021C0 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = ../WF_SDK/WebRTC.xcframework; sourceTree = "<group>"; };
 		B725837A2B0714F300C021C0 /* WFAVEngineKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WFAVEngineKit.xcframework; path = ../WF_SDK/WFAVEngineKit.xcframework; sourceTree = "<group>"; };
+		B725837E2B07299500C021C0 /* WFAVModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WFAVModule.h; sourceTree = "<group>"; };
+		B725837F2B07299500C021C0 /* WFAVModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WFAVModule.m; sourceTree = "<group>"; };
+		B72583822B0729C500C021C0 /* WFAVProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WFAVProxy.h; sourceTree = "<group>"; };
+		B72583832B0729C500C021C0 /* WFAVProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WFAVProxy.m; sourceTree = "<group>"; };
+		B72583862B072C5B00C021C0 /* WFAVRtcView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WFAVRtcView.h; sourceTree = "<group>"; };
+		B72583872B072C5B00C021C0 /* WFAVRtcView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WFAVRtcView.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -50,6 +62,12 @@
 		B72583642B07139800C021C0 /* WFAVUniPlugin */ = {
 			isa = PBXGroup;
 			children = (
+				B725837E2B07299500C021C0 /* WFAVModule.h */,
+				B725837F2B07299500C021C0 /* WFAVModule.m */,
+				B72583822B0729C500C021C0 /* WFAVProxy.h */,
+				B72583832B0729C500C021C0 /* WFAVProxy.m */,
+				B72583862B072C5B00C021C0 /* WFAVRtcView.h */,
+				B72583872B072C5B00C021C0 /* WFAVRtcView.m */,
 			);
 			path = WFAVUniPlugin;
 			sourceTree = "<group>";
@@ -70,6 +88,9 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				B72583882B072C5B00C021C0 /* WFAVRtcView.h in Headers */,
+				B72583802B07299500C021C0 /* WFAVModule.h in Headers */,
+				B72583842B0729C500C021C0 /* WFAVProxy.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -141,6 +162,9 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				B72583892B072C5B00C021C0 /* WFAVRtcView.m in Sources */,
+				B72583852B0729C500C021C0 /* WFAVProxy.m in Sources */,
+				B72583812B07299500C021C0 /* WFAVModule.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 17 - 0
uni-iOS-SDK/HBuilder-uniPluginDemo/WFAVUniPlugin/WFAVUniPlugin/WFAVModule.h

@@ -0,0 +1,17 @@
+//
+//  WFAVModule.h
+//  WFAVUniPlugin
+//
+//  Created by Rain on 2023/11/17.
+//
+
+#import "DCUniModule.h"
+
+NS_ASSUME_NONNULL_BEGIN
+@class WFAVRtcView;
+
+@interface WFAVModule : DCUniModule
+- (void)onViewCreated:(WFAVRtcView *)rtcView;
+@end
+
+NS_ASSUME_NONNULL_END

+ 835 - 0
uni-iOS-SDK/HBuilder-uniPluginDemo/WFAVUniPlugin/WFAVUniPlugin/WFAVModule.m

@@ -0,0 +1,835 @@
+//
+//  WFAVModule.m
+//  WFAVUniPlugin
+//
+//  Created by Rain on 2023/11/17.
+//
+
+#import "WFAVModule.h"
+#import "WFAVRtcView.h"
+#import <WFChatClient/WFCChatClient.h>
+#import <WFAVEngineKit/WFAVEngineKit.h>
+
+@interface WFAVCallSessionDelegater : NSObject <WFAVCallSessionDelegate>
+@property(nonatomic, strong)NSString *callId;
+@property (nonatomic, weak) DCUniSDKInstance *uniInstance;
+@end
+
+@implementation WFAVCallSessionDelegater
+- (instancetype)initWithCallId:(NSString *)callId uniInstance:(DCUniSDKInstance *)uniInstance {
+    self = [super init];
+    if(self) {
+        self.callId = callId;
+        self.uniInstance = uniInstance;
+    }
+    return self;
+}
+- (void)didCallEndWithReason:(WFAVCallEndReason)reason {
+    [self onIndication:@[@"didCallEndWithReason", @(reason)]];
+}
+
+- (void)didChangeInitiator:(NSString * _Nullable)initiator { 
+    [self onIndication:@[@"didChangeInitiator", initiator]];
+}
+
+- (void)didChangeMode:(BOOL)isAudioOnly { 
+    [self onIndication:@[@"didChangeMode", @(isAudioOnly)]];
+}
+
+- (void)didChangeState:(WFAVEngineState)state { 
+    [self onIndication:@[@"didChangeState", @(state)]];
+}
+
+- (void)didCreateLocalVideoTrack:(RTCVideoTrack * _Nonnull)localVideoTrack { 
+    [self onIndication:@[@"didCreateLocalVideoTrack"]];
+}
+
+- (void)didError:(NSError * _Nonnull)error { 
+    [self onIndication:@[@"didError", error.description]];
+}
+
+- (void)didGetStats:(NSArray * _Nonnull)stats { 
+    
+}
+
+- (void)didParticipantConnected:(NSString * _Nonnull)userId screenSharing:(BOOL)screenSharing { 
+    [self onIndication:@[@"didParticipantConnected", userId, @(screenSharing)]];
+}
+
+- (void)didParticipantJoined:(NSString * _Nonnull)userId screenSharing:(BOOL)screenSharing { 
+    [self onIndication:@[@"didParticipantJoined", userId, @(screenSharing)]];
+}
+
+- (void)didParticipantLeft:(NSString * _Nonnull)userId screenSharing:(BOOL)screenSharing withReason:(WFAVCallEndReason)reason { 
+    [self onIndication:@[@"didParticipantLeft", userId, @(screenSharing)]];
+}
+
+- (void)didReceiveRemoteVideoTrack:(RTCVideoTrack * _Nonnull)remoteVideoTrack fromUser:(NSString * _Nonnull)userId screenSharing:(BOOL)screenSharing { 
+    [self onIndication:@[@"didReceiveRemoteVideoTrack", userId, @(screenSharing)]];
+}
+
+- (void)didVideoMuted:(BOOL)videoMuted fromUser:(NSString * _Nonnull)userId { 
+    [self onIndication:@[@"didVideoMuted", userId, @(videoMuted)]];
+}
+
+- (void)didReportAudioVolume:(NSInteger)volume ofUser:(NSString *_Nonnull)userId {
+    [self onIndication:@[@"didReportAudioVolume", userId, @(volume)]];
+}
+
+- (void)didChangeType:(BOOL)audience ofUser:(NSString *_Nonnull)userId {
+    [self onIndication:@[@"didChangeType", userId, @(audience), @(NO)]];
+}
+
+- (void)didChangeAudioRoute {
+/*
+public static enum AudioDevice {
+ SPEAKER_PHONE,
+ WIRED_HEADSET,
+ EARPIECE,
+ BLUETOOTH,
+ NONE;
+}
+*/
+    int audioDevice;
+    if([[WFAVEngineKit sharedEngineKit].currentSession isSpeaker]) {
+        audioDevice = 0;
+    } else if([[WFAVEngineKit sharedEngineKit].currentSession isHeadsetPluggedIn]) {
+        audioDevice = 1;
+    } else if([[WFAVEngineKit sharedEngineKit].currentSession isBluetoothSpeaker]) {
+        audioDevice = 3;
+    } else {
+        audioDevice = 2;
+    }
+    [self onIndication:@[@"didAudioDeviceChanged", @(audioDevice)]];
+}
+
+- (void)didMuteStateChanged:(NSArray<NSString *> *_Nonnull)userIds {
+    [self onIndication:@[@"didMuteStateChanged", userIds]];
+}
+
+- (void)didMedia:(NSString *_Nullable)media lostPackage:(int)lostPackage screenSharing:(BOOL)screenSharing {
+    [self onIndication:@[@"didMediaLostPacket", media, @(lostPackage), @(screenSharing)]];
+}
+
+- (void)didMedia:(NSString *_Nullable)media lostPackage:(int)lostPackage uplink:(BOOL)uplink ofUser:(NSString *_Nonnull)userId screenSharing:(BOOL)screenSharing {
+    [self onIndication:@[@"didUserMediaLostPacket", userId, media, @(lostPackage), @(screenSharing)]];
+}
+
+- (void)onIndication:(NSArray *)args {
+    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
+    dict[@"args"] = args;
+    dict[@"timestamp"] = @([[[NSDate alloc] init] timeIntervalSince1970]);
+    dict[@"callId"] = self.callId;
+    [self.uniInstance fireGlobalEvent:@"wfc-av-session-event" params:dict];
+}
+@end
+
+
+
+@interface WFAVModule () <WFAVEngineDelegate>
+@property(nonatomic, strong)NSMutableDictionary<WFAVRtcView*, NSArray*> *componentStringMap;
+@property(nonatomic, strong)NSMutableDictionary<NSString *, WFAVCallSessionDelegater*> *delegaterMap;
+@end
+
+WFAVModule *gWFAVModule = nil;
+
+@implementation WFAVModule
+//@UniJSMethod(uiThread = true)
+//public void initAVEngineKit() {
+//    uniSDKInstance = mUniSDKInstance;
+//    AVEngineKit.init(uniSDKInstance.getContext(), AVEngineCallbackWrapper.INSTANCE);
+//    AVEngineKit.DISABLE_SURFACE_VIEW_AUTO_OVERLAY = true;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(initAVEngineKit))
+- (void)initAVEngineKit {
+    NSLog(@"call client init");
+    [WFAVEngineKit notRegisterVoipPushService];
+    [WFAVEngineKit sharedEngineKit].delegate = self;
+    gWFAVModule = self;
+    self.componentStringMap = [[NSMutableDictionary alloc] init];
+    self.delegaterMap = [[NSMutableDictionary alloc] init];
+}
+
+///**
+// * sdk后处理
+// */
+//@Override
+//public void onActivityDestroy() {
+//    super.onActivityDestroy();
+//    componentStringMap.clear();
+//    // 删除监听器
+//    Log.i(TAG, "应用销毁后处理");
+//}
+//
+//@UniJSMethod(uiThread = false)
+//public void addICEServer(String url, String name, String password) {
+//    AVEngineKit.Instance().addIceServer(url, name, password);
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(addICEServer:name:password:))
+- (void)addICEServer:(NSString *)url name:(NSString *)name password:(NSString *)password {
+    [[WFAVEngineKit sharedEngineKit] addIceServer:url userName:name password:password];
+}
+
+//@UniJSMethod(uiThread = false)
+//public String startSingleCall(String target, boolean audioOnly) {
+//    return startSingleCallWithLine(target, 0, audioOnly);
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(startSingleCall:audioOnly:))
+- (NSString *)startSingleCall:(NSString *)userId audioOnly:(BOOL)audioOnly {
+    return [self startSingleCallWithLine:userId line:0 audioOnly:audioOnly];
+}
+//@UniJSMethod(uiThread = false)
+//public String startSingleCallWithLine(String target, int line, boolean audioOnly) {
+//    AVEngineKit.DISABLE_SURFACE_VIEW_AUTO_OVERLAY = false;
+//    Conversation conversation = new Conversation(Conversation.ConversationType.Single, target, line);
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().startCall(conversation, Collections.singletonList(conversation.target), audioOnly, CallSessionCallbackWrapper.INSTANCE);
+//    if (session != null) {
+//        AudioManager audioManager = (AudioManager) uniSDKInstance.getContext().getSystemService(Context.AUDIO_SERVICE);
+//        audioManager.setMode(audioOnly ? AudioManager.MODE_IN_COMMUNICATION : AudioManager.MODE_NORMAL);
+//        audioManager.setSpeakerphoneOn(!audioOnly);
+//        return JSONObject.toJSONString(JSCallSession.fromCallSession(session), ClientUniAppHookProxy.serializeConfig);
+//    }
+//    return null;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(startSingleCallWithLine:line:audioOnly:))
+- (NSString *)startSingleCallWithLine:(NSString *)userId line:(int)line audioOnly:(BOOL)audioOnly {
+    WFAVCallSessionDelegater *delegater = [[WFAVCallSessionDelegater alloc] initWithCallId:nil uniInstance:self.uniInstance];
+    WFAVCallSession *session = [[WFAVEngineKit sharedEngineKit] startCall:@[userId] audioOnly:audioOnly callExtra:nil conversation:[WFCCConversation conversationWithType:Single_Type target:userId line:line] sessionDelegate:delegater];
+    if(session) {
+        [self.delegaterMap setValue:delegater forKey:session.callId];
+        return [self callSession2String:session];
+    }
+    return nil;
+}
+
+//@UniJSMethod(uiThread = true)
+//public void leaveConference(String callId, boolean destroyRoom) {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null && TextUtils.equals(session.getCallId(), callId)) {
+//        session.leaveConference(destroyRoom);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(leaveConference:destroyRoom:))
+- (void)leaveConference:(NSString *)callId destroyRoom:(BOOL)destroyRoom {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session != nil && [session.callId isEqualToString:callId]) {
+        [session leaveConference:destroyRoom];
+    }
+}
+
+//public void kickoffParticipant(String callId, String userId, JSCallback successCB, JSCallback failCB) {
+//    JSAVGeneralCallback jsavGeneralCallback = new JSAVGeneralCallback(successCB, failCB);
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null && TextUtils.equals(session.getCallId(), callId)) {
+//        session.kickoffParticipant(userId, jsavGeneralCallback);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(kickoffParticipant:userId:success:error:))
+- (void)kickoffParticipant:(NSString *)callId userId:(NSString *)userId success:(UniModuleKeepAliveCallback)successCB error:(UniModuleKeepAliveCallback)errorCB {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session != nil && [session.callId isEqualToString:callId]) {
+        [session kickoffParticipant:userId success:^{
+            successCB(nil, false);
+        } error:^(int error_code) {
+            errorCB(@(error_code), NO);
+        }];
+    }
+}
+
+//private Map<WXComponent, Pair<String, Boolean>> componentStringMap = new WeakHashMap<>();
+//
+//@UniJSMethod(uiThread = true)
+//public void setLocalVideoView(String userId, String ref) {
+//    Log.d(TAG, "setLocalVideoView " + userId + " " + ref);
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session == null) {
+//        return;
+//    }
+//    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(this.mWXSDKInstance.getInstanceId(), ref);
+//    FrameLayout frameLayout = (FrameLayout) component.getHostView();
+//    if (frameLayout == null) {
+//        Log.e(TAG, "setLocalVideoView frameLayout is null");
+//        this.mWXSDKInstance.setComponentObserver(this);
+//        componentStringMap.put(component, new Pair<>(userId, false));
+//    } else {
+//        session.setupLocalVideoView(frameLayout, RendererCommon.ScalingType.SCALE_ASPECT_BALANCED);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(setLocalVideoView:view:))
+- (void)setLocalVideoView:(NSString *)callId view:(NSString *)viewRef {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    
+    if([session.callId isEqualToString:callId]) {
+        WXComponent *component = [self.uniInstance.componentManager componentForRef:viewRef];
+        if(component.view == nil) {
+            self.componentStringMap[component] = @[[WFCCNetworkService sharedInstance].userId, @(false)];
+        } else {
+            [session setupLocalVideoView:component.view scalingType:kWFAVVideoScalingTypeAspectBalanced];
+        }
+    }
+}
+
+//@UniJSMethod(uiThread = true)
+//public void setRemoteVideoView(String userId, boolean screenSharing, String ref) {
+//    Log.d(TAG, "setRemoteVideoView " + userId + " " + screenSharing + " " + ref);
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session == null) {
+//        return;
+//    }
+//
+//    WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(this.mWXSDKInstance.getInstanceId(), ref);
+//    FrameLayout frameLayout = (FrameLayout) component.getHostView();
+//    if (frameLayout == null) {
+//        Log.e(TAG, "setRemoteVideoView frameLayout is null");
+//        this.mWXSDKInstance.setComponentObserver(this);
+//        componentStringMap.put(component, new Pair<>(userId, screenSharing));
+//    } else {
+//        this.resetRemoteVideoViewLayoutParams(frameLayout);
+//        Log.d(TAG, "setRemoteVideoView " + userId + " " + screenSharing + " " + frameLayout);
+//        session.setupRemoteVideoView(userId, screenSharing, frameLayout, RendererCommon.ScalingType.SCALE_ASPECT_BALANCED);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(setRemoteVideoView:screenSharing:view:))
+- (void)setRemoteVideoView:(NSString *)userId screenSharing:(BOOL)screenSharing view:(NSString *)viewRef {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    
+//    if([session.callId isEqualToString:callId]) {
+        WXComponent *component = [self.uniInstance.componentManager componentForRef:viewRef];
+        if(component.view == nil) {
+            self.componentStringMap[component] = @[userId, @(screenSharing)];
+        } else {
+            [session setupRemoteVideoView:component.view scalingType:kWFAVVideoScalingTypeAspectBalanced forUser:userId screenSharing:screenSharing];
+        }
+//    }
+}
+//@UniJSMethod(uiThread = true)
+//public void setParticipantVideoType(String userId, boolean screenSharing, int videoType) {
+//    if (videoType < 0 || videoType > 2) {
+//        Log.e(TAG, "setParticipantVideoType videoType error: " + videoType);
+//        return;
+//    }
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        session.setParticipantVideoType(userId, screenSharing, AVEngineKit.VideoType.values()[videoType]);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(setParticipantVideoType:screenSharing:videoType:))
+- (void)setParticipantVideoType:(NSString *)userId screenSharing:(BOOL)screenSharing videoType:(int)videoType {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    
+    if (videoType < 0 || videoType > 2) {
+        return;
+    }
+    
+    [session setParticipant:userId screenSharing:screenSharing videoType:(WFAVVideoType)videoType];
+}
+//@UniJSMethod(uiThread = false)
+//public String getParticipantProfiles() {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        List<AVEngineKit.ParticipantProfile> profiles = session.getParticipantProfiles();
+//        return JSONObject.toJSONString(profiles, ClientUniAppHookProxy.serializeConfig);
+//    }
+//    return null;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(getParticipantProfiles))
+- (NSString *)getParticipantProfiles {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return nil;
+    }
+    
+    NSArray<WFAVParticipantProfile *> *profiles = session.participants;
+    NSMutableArray<NSDictionary *> *dicts = [[NSMutableArray alloc] init];
+    [profiles enumerateObjectsUsingBlock:^(WFAVParticipantProfile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        [dicts addObject:[self profile2Dict:obj]];
+    }];
+    return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:dicts options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];
+}
+//@UniJSMethod(uiThread = false)
+//public String getParticipantProfile(String userId, boolean screenSharing) {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        AVEngineKit.ParticipantProfile profile = session.getParticipantProfile(userId, screenSharing);
+//        return JSONObject.toJSONString(profile, ClientUniAppHookProxy.serializeConfig);
+//    }
+//    return null;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(getParticipantProfile:screenSharing:))
+- (NSString *)getParticipantProfile:(NSString *)userId screenSharing:(BOOL)screenSharing {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return nil;
+    }
+    
+    WFAVParticipantProfile *profile = [session profileOfUser:userId isScreenSharing:screenSharing];
+    return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:[self profile2Dict:profile] options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];
+}
+
+//@UniJSMethod(uiThread = false)
+//public String getMyProfile() {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        AVEngineKit.ParticipantProfile profile = session.getMyProfile();
+//        return JSONObject.toJSONString(profile, ClientUniAppHookProxy.serializeConfig);
+//    }
+//    return null;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(getMyProfile))
+- (NSString *)getMyProfile {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return nil;
+    }
+    
+    WFAVParticipantProfile *profile = session.myProfile;
+    return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:[self profile2Dict:profile] options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];
+}
+
+//@UniJSMethod(uiThread = false)
+//public void muteAudio(boolean mute) {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        session.muteAudio(mute);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(muteAudio:))
+- (void)muteAudio:(BOOL)mute {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    
+    [session muteAudio:mute];
+}
+
+//@UniJSMethod(uiThread = false)
+//public void muteVideo(boolean mute) {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        session.muteVideo(mute);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(muteVideo:))
+- (void)muteVideo:(BOOL)mute {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    
+    [session muteVideo:mute];
+}
+
+//@UniJSMethod(uiThread = true)
+//public void setSpeakerOn(boolean speakerOn) {
+//    AVAudioManager audioManager = AVEngineKit.Instance().getAVAudioManager();
+//    AVAudioManager.AudioDevice currentAudioDevice = audioManager.getSelectedAudioDevice();
+//    if (currentAudioDevice == AVAudioManager.AudioDevice.WIRED_HEADSET || currentAudioDevice == AVAudioManager.AudioDevice.BLUETOOTH) {
+//        Log.d(TAG, "setSpeakerOn failed, current audio device: " + currentAudioDevice.name());
+//        return;
+//    }
+//    audioManager.selectAudioDevice(speakerOn ? AVAudioManager.AudioDevice.SPEAKER_PHONE : AVAudioManager.AudioDevice.EARPIECE);
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(setSpeakerOn:))
+- (void)setSpeakerOn:(BOOL)speakerOn {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    
+    [session enableSpeaker:speakerOn];
+}
+
+//@UniJSMethod(uiThread = true)
+//public void downgrade2Voice() {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        session.setAudioOnly(true);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(downgrade2Voice))
+- (void)downgrade2Voice {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    
+    [session setAudioOnly:YES];
+}
+
+//@UniJSMethod(uiThread = false)
+//public String startMultiCall(String groupId, List<String> participants, boolean audioOnly) {
+//    AVEngineKit.DISABLE_SURFACE_VIEW_AUTO_OVERLAY = true;
+//    Conversation conversation = new Conversation(Conversation.ConversationType.Group, groupId);
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().startCall(conversation, participants, audioOnly, CallSessionCallbackWrapper.INSTANCE);
+//    if (session != null) {
+//        AudioManager audioManager = (AudioManager) uniSDKInstance.getContext().getSystemService(Context.AUDIO_SERVICE);
+//        audioManager.setMode(AudioManager.MODE_NORMAL);
+//        audioManager.setSpeakerphoneOn(true);
+//        return JSONObject.toJSONString(JSCallSession.fromCallSession(session), ClientUniAppHookProxy.serializeConfig);
+//    }
+//    return null;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(startMultiCall:participants:audioOnly:))
+- (NSString *)startMultiCall:(NSString *)groupId participants:(NSArray<NSString *> *)participants audioOnly:(BOOL)audioOnly {
+    WFCCConversation *conversation = [WFCCConversation conversationWithType:Group_Type target:groupId line:0];
+    WFAVCallSessionDelegater *delegater = [[WFAVCallSessionDelegater alloc] initWithCallId:nil uniInstance:self.uniInstance];
+    WFAVCallSession *session = [[WFAVEngineKit sharedEngineKit] startCall:participants audioOnly:audioOnly callExtra:nil conversation:conversation sessionDelegate:delegater];
+    if(session) {
+        [self.delegaterMap setObject:delegater forKey:session.callId];
+        return [self callSession2String:session];
+    }
+    return nil;
+}
+
+//@UniJSMethod(uiThread = false)
+//public String startConference(String callId, boolean audioOnly, String pin, String host, String title, String desc, boolean audience, boolean advance, boolean record, String callExtra) {
+//    AVEngineKit.DISABLE_SURFACE_VIEW_AUTO_OVERLAY = true;
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().startConference(callId, audioOnly, pin, host, title, desc, audience, advance, record, CallSessionCallbackWrapper.INSTANCE);
+//    if (session != null) {
+//        return JSONObject.toJSONString(JSCallSession.fromCallSession(session), ClientUniAppHookProxy.serializeConfig);
+//    } else {
+//        return null;
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(startConference:audioOnly:pin:host:title:desc:audience:advanced:record:callExtra:))
+- (NSString *)startConference:(NSString *)callId audioOnly:(BOOL)audioOnly pin:(NSString *)pin host:(NSString *)host title:(NSString * _Nullable)title desc:(NSString * _Nullable)desc audience:(BOOL)audience advanced:(BOOL)advanced record:(BOOL)record callExtra:(NSString * _Nullable)callExtra {
+    WFAVCallSessionDelegater *delegater = [[WFAVCallSessionDelegater alloc] initWithCallId:nil uniInstance:self.uniInstance];
+    WFAVCallSession *session = [[WFAVEngineKit sharedEngineKit] startConference:callId audioOnly:audioOnly pin:pin host:host title:title desc:desc callExtra:callExtra audience:audience advanced:advanced record:record maxParticipants:20 sessionDelegate:delegater];
+    if(session) {
+        [self.delegaterMap setObject:delegater forKey:session.callId];
+        return [self callSession2String:session];
+    }
+    return nil;
+}
+
+//@UniJSMethod(uiThread = false)
+//public String joinConference(String callId, boolean audioOnly, String pin, String host, String title, String desc, boolean audience, boolean advance, boolean muteAudio, boolean muteVideo, String extra) {
+//    AVEngineKit.DISABLE_SURFACE_VIEW_AUTO_OVERLAY = true;
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().joinConference(callId, audioOnly, pin, host, title, desc, audience, advance, muteAudio, muteVideo, CallSessionCallbackWrapper.INSTANCE);
+//    if (session != null) {
+//        return JSONObject.toJSONString(JSCallSession.fromCallSession(session), ClientUniAppHookProxy.serializeConfig);
+//    }
+//    return null;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(joinConference:audioOnly:pin:host:title:desc:audience:advanced:muteAudio:muteVideo:callExtra:))
+- (NSString *)joinConference:(NSString *)callId audioOnly:(BOOL)audioOnly pin:(NSString *)pin host:(NSString *)host title:(NSString * _Nullable)title desc:(NSString * _Nullable)desc audience:(BOOL)audience advanced:(BOOL)advanced muteAudio:(BOOL)muteAudio muteVideo:(BOOL)muteVideo callExtra:(NSString * _Nullable)callExtra {
+    WFAVCallSessionDelegater *delegater = [[WFAVCallSessionDelegater alloc] initWithCallId:nil uniInstance:self.uniInstance];
+    WFAVCallSession *session = [[WFAVEngineKit sharedEngineKit] joinConference:callId audioOnly:audioOnly pin:pin host:host title:title desc:desc callExtra:callExtra audience:audience advanced:advanced muteAudio:muteAudio muteVideo:muteVideo sessionDelegate:delegater];
+    if(session) {
+        [self.delegaterMap setObject:delegater forKey:session.callId];
+        return [self callSession2String:session];
+    }
+    return nil;
+}
+
+//@UniJSMethod(uiThread = false)
+//public boolean isSupportMultiCall() {
+//    return AVEngineKit.isSupportMultiCall();
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(isSupportMultiCall))
+- (BOOL)isSupportMultiCall {
+    return YES;
+}
+//@UniJSMethod(uiThread = false)
+//public boolean isSupportConference() {
+//    return AVEngineKit.isSupportConference();
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(isSupportConference))
+- (BOOL)isSupportConference {
+    return [WFAVEngineKit sharedEngineKit].supportConference;
+}
+
+//@UniJSMethod(uiThread = false)
+//public void setVideoProfile(int profile, boolean swapWidthHeight) {
+//    AVEngineKit.Instance().setVideoProfile(profile, swapWidthHeight);
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(setVideoProfile:swapWidthHeight:))
+- (void)setVideoProfile:(int)profile swapWidthHeight:(BOOL)swapWidthHeight {
+    [[WFAVEngineKit sharedEngineKit] setVideoProfile:profile swapWidthHeight:swapWidthHeight];
+}
+
+//
+//
+//@UniJSMethod(uiThread = false)
+//public void answerCall(String callId, boolean audioOnly) {
+//    AVEngineKit.CallSession callSession = AVEngineKit.Instance().getCurrentSession();
+//    if (callSession != null
+//        && TextUtils.equals(callId, callSession.getCallId())
+//        && callSession.getState() == AVEngineKit.CallState.Incoming) {
+//        callSession.setCallback(CallSessionCallbackWrapper.INSTANCE);
+//        Conversation conversation = callSession.getConversation();
+//        if (conversation.type == Conversation.ConversationType.Single) {
+//            AVEngineKit.DISABLE_SURFACE_VIEW_AUTO_OVERLAY = false;
+//        } else {
+//            AVEngineKit.DISABLE_SURFACE_VIEW_AUTO_OVERLAY = true;
+//        }
+//        callSession.answerCall(audioOnly);
+//    } else {
+//        // TODO
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(answerCall:audioOnly:))
+- (void)answerCall:(NSString *)callId audioOnly:(BOOL)audioOnly {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    if([session.callId isEqualToString:callId]) {
+        [session answerCall:audioOnly callExtra:nil];
+    }
+}
+
+//@UniJSMethod(uiThread = true)
+//public void endCall(String callId) {
+//    Log.e(TAG, "endCall " + callId);
+//    AVEngineKit.CallSession callSession = AVEngineKit.Instance().getCurrentSession();
+//    if (callSession != null
+//        && (callSession.getState() != AVEngineKit.CallState.Idle
+//        && callSession.getCallId().equals(callId))) {
+//        callSession.endCall();
+//        callSession.setCallback(null);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(endCall:))
+- (void)endCall:(NSString *)callId {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    if([session.callId isEqualToString:callId]) {
+        [session endCall];
+    }
+}
+
+//@UniJSMethod(uiThread = false)
+//public String currentCallSession() {
+//    AVEngineKit.CallSession callSession = AVEngineKit.Instance().getCurrentSession();
+//    if (callSession == null) {
+//        return null;
+//    }
+//    return JSONObject.toJSONString(JSCallSession.fromCallSession(callSession), ClientUniAppHookProxy.serializeConfig);
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(currentCallSession))
+- (NSString *)currentCallSession {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(!session || session.state == kWFAVEngineStateIdle) {
+        return nil;
+    }
+    return [self callSession2String:session];
+}
+
+//@UniJSMethod(uiThread = false)
+//public boolean canSwitchAudience() {
+//    if (AVEngineKit.isSupportConference()) {
+//        AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//        return session != null && session.canSwitchAudience();
+//    }
+//    return false;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(canSwitchAudience))
+- (BOOL)canSwitchAudience {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(!session || session.state == kWFAVEngineStateIdle) {
+        return NO;
+    }
+    if([self isSupportConference]) {
+        return [session canSwitchAudience];
+    }
+    return NO;
+}
+
+//@UniJSMethod(uiThread = false)
+//public boolean switchAudience(boolean audience) {
+//    if (AVEngineKit.isSupportConference()) {
+//        AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//        return session != null && session.switchAudience(audience);
+//    }
+//    return false;
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(switchAudience:))
+- (BOOL)switchAudience:audience {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(!session || session.state == kWFAVEngineStateIdle) {
+        return NO;
+    }
+    if([self isSupportConference]) {
+        return [session switchAudience:audience];
+    }
+    return NO;
+}
+
+//@UniJSMethod(uiThread = true)
+//public void switchCamera() {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        session.switchCamera();
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(switchCamera))
+- (void)switchCamera {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(!session || session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    [session switchCamera];
+}
+
+//@UniJSMethod(uiThread = true)
+//public void inviteNewParticipant(List<String> userIds) {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session != null) {
+//        session.inviteNewParticipants(userIds);
+//    }
+//}
+UNI_EXPORT_METHOD_SYNC(@selector(inviteNewParticipant:))
+- (void)inviteNewParticipant:(NSArray<NSString *> *)participants {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(!session || session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    [session inviteNewParticipants:participants];
+}
+
+//@Override
+//public void onCreate(WXComponent component) {
+//
+//}
+//
+//@Override
+//public void onPreDestory(WXComponent component) {
+//
+//}
+//
+//@Override
+//public void onViewCreated(WXComponent component, View view) {
+//    AVEngineKit.CallSession session = AVEngineKit.Instance().getCurrentSession();
+//    if (session == null) {
+//        return;
+//    }
+//    for (Map.Entry<WXComponent, Pair<String, Boolean>> entry : componentStringMap.entrySet()) {
+//        WXComponent wxComponent = entry.getKey();
+//        if (component == wxComponent) {
+//            Pair<String, Boolean> pair = entry.getValue();
+//            if (pair.first.equals(ChatManager.Instance().getUserId())) {
+//                session.setupLocalVideoView((FrameLayout) wxComponent.getHostView(), RendererCommon.ScalingType.SCALE_ASPECT_BALANCED);
+//            } else {
+//                FrameLayout frameLayout = (FrameLayout) wxComponent.getHostView();
+//                this.resetRemoteVideoViewLayoutParams(frameLayout);
+//                session.setupRemoteVideoView(pair.first, pair.second, frameLayout, RendererCommon.ScalingType.SCALE_ASPECT_BALANCED);
+//            }
+//        }
+//    }
+//    componentStringMap.remove(component);
+//}
+- (void)onViewCreated:(WFAVRtcView *)rtcView {
+    WFAVCallSession *session = [WFAVEngineKit sharedEngineKit].currentSession;
+    if(session.state == kWFAVEngineStateIdle) {
+        return;
+    }
+    
+    NSArray *arr = self.componentStringMap[rtcView];
+    if(arr) {
+        NSString *userId = arr[0];
+        BOOL screenSharing = [arr[1] boolValue];
+        if([userId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
+            [session setupLocalVideoView:rtcView.view scalingType:kWFAVVideoScalingTypeAspectBalanced];
+        } else {
+            [session setupRemoteVideoView:rtcView.view scalingType:kWFAVVideoScalingTypeAspectBalanced forUser:userId screenSharing:screenSharing];
+        }
+        [self.componentStringMap removeObjectForKey:rtcView];
+    }
+}
+
+- (NSString *)callSession2String:(WFAVCallSession *)session {
+    if(!session || session.state == kWFAVEngineStateIdle) {
+        return nil;
+    }
+    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
+    dict[@"callId"] = session.callId;
+    if(session.initiator.length) {
+        dict[@"initiator"] = session.initiator;
+    }
+    if(session.inviter.length) {
+        dict[@"inviter"] = session.inviter;
+    }
+    dict[@"state"] = @(session.state);
+    dict[@"startTime"] = @(session.startTime);
+    dict[@"connectedTime"] = @(session.connectedTime);
+    dict[@"endTime"] = @(session.endTime);
+    if(session.conversation) {
+        dict[@"conversation"] = [session.conversation toJsonObj];
+    }
+    dict[@"audioOnly"] = @(session.audioOnly);
+    dict[@"endReason"] = @(session.endReason);
+    dict[@"conference"] = @(session.conference);
+    dict[@"audience"] = @(session.audience);
+    dict[@"advanced"] = @(session.advanced);
+    dict[@"multiCall"] = @(session.multiCall);
+    return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:nil] encoding:NSUTF8StringEncoding];
+}
+
+- (NSDictionary *)profile2Dict:(WFAVParticipantProfile *)profile {
+    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
+    
+    dict[@"userId"] = profile.userId;
+    dict[@"startTime"] = @(profile.startTime);
+    dict[@"state"] = @(profile.state);
+    dict[@"videoMuted"] = @(profile.videoMuted);
+    dict[@"audioMuted"] = @(profile.audioMuted);
+    dict[@"audience"] = @(profile.audience);
+    dict[@"screeSharing"] = @(profile.screeSharing);
+    dict[@"callExtra"] = profile.callExtra;
+    dict[@"videoType"] = @(profile.videoType);
+    
+    return dict;
+}
+
+- (void)onIndication:(NSArray *)args {
+    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
+    dict[@"args"] = args;
+    dict[@"timestamp"] = @([[[NSDate alloc] init] timeIntervalSince1970]);
+    [self.uniInstance fireGlobalEvent:@"wfc-av-event" params:dict];
+}
+
+#pragma mark - WFAVEngineDelegate
+- (void)didReceiveCall:(WFAVCallSession *)session {
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        if ([WFAVEngineKit sharedEngineKit].currentSession.state != kWFAVEngineStateIncomming && [WFAVEngineKit sharedEngineKit].currentSession.state != kWFAVEngineStateConnected && [WFAVEngineKit sharedEngineKit].currentSession.state != kWFAVEngineStateConnecting) {
+            return;
+        }
+        
+        [self onIndication:@[@"onReceiveCall", [self callSession2String:session]]];
+    });
+}
+
+- (void)shouldStartRing:(BOOL)isIncoming {
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        if ([WFAVEngineKit sharedEngineKit].currentSession.state == kWFAVEngineStateIncomming || [WFAVEngineKit sharedEngineKit].currentSession.state == kWFAVEngineStateOutgoing) {
+            [self onIndication:@[@"shouldStartRing", @(isIncoming)]];
+        }
+    });
+}
+
+- (void)shouldStopRing {
+    [self onIndication:@[@"shouldStopRing"]];
+}
+
+- (void)didCallEnded:(WFAVCallEndReason) reason duration:(int)callDuration {
+    [self onIndication:@[@"didCallEnded", @(reason), @(callDuration)]];
+    [self.componentStringMap removeAllObjects];
+}
+
+- (void)didReceiveIncomingPushWithPayload:(PKPushPayload * _Nonnull)payload forType:(NSString * _Nonnull)type {
+    
+}
+@end

+ 17 - 0
uni-iOS-SDK/HBuilder-uniPluginDemo/WFAVUniPlugin/WFAVUniPlugin/WFAVProxy.h

@@ -0,0 +1,17 @@
+//
+//  WFAVProxy.h
+//  WFAVUniPlugin
+//
+//  Created by Rain on 2023/11/17.
+//
+
+#import <Foundation/Foundation.h>
+#import "UniPluginProtocol.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WFAVProxy : NSObject<UniPluginProtocol>
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 12 - 0
uni-iOS-SDK/HBuilder-uniPluginDemo/WFAVUniPlugin/WFAVUniPlugin/WFAVProxy.m

@@ -0,0 +1,12 @@
+//
+//  WFAVProxy.m
+//  WFAVUniPlugin
+//
+//  Created by Rain on 2023/11/17.
+//
+
+#import "WFAVProxy.h"
+
+@implementation WFAVProxy
+
+@end

+ 17 - 0
uni-iOS-SDK/HBuilder-uniPluginDemo/WFAVUniPlugin/WFAVUniPlugin/WFAVRtcView.h

@@ -0,0 +1,17 @@
+//
+//  WFAVRtcView.h
+//  WFAVUniPlugin
+//
+//  Created by Rain on 2023/11/17.
+//
+
+#import <UIKit/UIKit.h>
+#import "DCUniComponent.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WFAVRtcView : DCUniComponent
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 36 - 0
uni-iOS-SDK/HBuilder-uniPluginDemo/WFAVUniPlugin/WFAVUniPlugin/WFAVRtcView.m

@@ -0,0 +1,36 @@
+//
+//  WFAVRtcView.m
+//  WFAVUniPlugin
+//
+//  Created by Rain on 2023/11/17.
+//
+
+#import "WFAVRtcView.h"
+#import "WFAVModule.h"
+
+
+extern WFAVModule *gWFAVModule;
+@interface WFAVRtcView ()
+@property(nonatomic, strong)UIView *nativeView;
+@end
+
+@implementation WFAVRtcView
+-(void)onCreateComponentWithRef:(NSString *)ref type:(NSString *)type
+                    styles:(NSDictionary *)styles
+                    attributes:(NSDictionary *)attributes
+                         events:(NSArray *)events uniInstance:(DCUniSDKInstance *)uniInstance {
+    [super onCreateComponentWithRef:ref type:type styles:styles attributes:attributes events:events uniInstance:uniInstance];
+    
+}
+
+- (UIView *)loadView {
+    if(!self.nativeView) {
+        self.nativeView = [[UIView alloc] init];
+    }
+    return self.nativeView;
+}
+
+-(void)viewWillLoad {
+    [gWFAVModule onViewCreated:self];
+}
+@end