会捷通客户端 SDK (macOS 版) 开发文档
会捷通客户端 SDK (macOS 版) 开发文档
概述
会捷通客户端 SDK 是⼀款视频会议软终端开发套件,开发者可以利⽤本 SDK 开发出具有清晰流畅的⾳视频体验和⾼清内容协作的⾳视频会议终端应用。会捷通客户端 SDK 具备强⼤的⽹络适应性,和独特的⾳视频抗⽹络丢包算法,配合会捷通云视讯平台使⽤,可以保证在 30% ⽹络丢包环境下视频依然清晰流畅,即使⽹络丢包⾼达 50%,依然可以保证⾳频通畅。 会捷通客户端 SDK 提供了丰富,⽽且简单易⽤的 API 接⼝。开发者不需要掌握丰富的⾳视频和信令相关知识,也可以使⽤本 SDK 开发出专业的视频会议软终端应用。 本⽂档详细介绍了 SDK 的各项功能,以及它们的使⽤⽅法。
系统要求
- macOS 10.12 及以上
开发环境
- xcode 10.0 及以上
示例代码
示例代码下载地址 GitHub (opens new window)
代码构成
HJT-SDK-macOS-Demo - 根目录
branding - 定制化脚本等
- customize.sh
- AppIcon.appiconset - logo 图标目录
easyVideo - Demo 工程目录
easyVideo.xcworkspace - xcode workspace
easyVideo.xcodeproj - xcode project
evsdk.framework - 会捷通客户端 SDK framework
Podfile - 定义通过 Pods 引入的第三方库
build.sh - 命令行编译脚本,可用于生成 Release 版本
easyVideo - Demo 代码目录
AppDelegate.m
AppDelegate.h
Components
Resources
- rootca.pem - 根证书文件
- bg_videomute.png - 关闭摄像头时使用的视频背景图片
- image_defaultuser.png - 默认头像图片
- speaker.wav
- ringtone.wav
- camera.wav
CustomView
Info.plist
ViewController - UI 主要实现代码目录
- ChangePasswordWindow
- InvitationWindow
- LoginWindow
- UserWindow
- HomeWindow
- JoinMeetingWindow
- VideoWindow
- PasswordWindow
en.lproj
zh-Hans.lproj
Assets.xcassets - 图片等资源文件目录
easyVideo.entitlements
easyVideo.pch
main.m
Base.lproj
编译示例工程
首先需要安装由 Pods 引入的依赖库,然后可以选择方法一或者方法二完成工程的编译
安装 Pods 引用
pod install
方法一、使用 xcode 编译工程
- 使用 xcode 打开 easyVideo 目录下的
easyVideo.xcworkspace
- 编译工程
- 使用 xcode 打开 easyVideo 目录下的
方法二、使用 easyVideo 目录下的
build.sh
以 Release Configuration 编译工程,生成结果在 easyVideo 目录下的build/Build/Products/Release/
内注意,实际使用时,需要根据需要更改
build.sh
中所指定的 Distribution Provion 文件信息,以及 PRODUCT_BUNDLE_IDENTIFIER 和 PRODUCT_NAME。#!/bin/sh # build.sh xcodebuild -workspace easyVideo.xcworkspace/ -configuration Release -scheme easyVideo -derivedDataPath ./build xcodebuild -project easyVideo.xcodeproj/ -configuration Release -scheme easyVideo -derivedDataPath ./build CODE_SIGN_IDENTITY="Developer ID Application: Beijing Zhong Chuang Shi Xun Technology Co., Ltd. (W269R3L92R)" DEVELOPMENT_TEAM="W269R3L92R" PRODUCT_BUNDLE_IDENTIFIER="com.hexmeet.hjtsdk" PROVISIONING_PROFILE_SPECIFIER="HexMeetHJT-Mac-Distribution" PROVISIONING_PROFILE="23dc7444-4491-4d38-87d5-7956b43373d6" PRODUCT_NAME="HJTSDK"
快速定制化
如果我们的示例工程满足您的产品需要,但是需要更换应用 Logo 以及公司版权信息,仅需进行非常少量的图片替换,以及本地化语言文件的修改,即可构建出符合您需要的专属定制化客户端应用。具体方法可以参考示例代码中 branding
目录下的 customize.sh
。customize.sh
脚本中执行的文件拷贝和字符串替换等操作,也可以通过手工方式完成。
#!/bin/bash
# customize.sh
# 替换 App 显示在系统中名字
sed -i "" -e "s/easyVideo/好应用/g" ../easyVideo/easyVideo/zh-Hans.lproj/InfoPlist.strings
sed -i "" -e "s/easyVideo/GreatAPP/g" ../easyVideo/easyVideo/en.lproj/InfoPlist.strings
# 替换版权信息显示的公司名字,根据需要您还可以替换更多文字
sed -i "" -e "s/北京中创视讯科技有限公司/伟大的公司/g" ../easyVideo/easyVideo/zh-Hans.lproj/localization.strings
sed -i "" -e "s/Beijing Zhong Chuang Shi Xun Technology Co., Ltd./Great Company/g" ../easyVideo/easyVideo/en.lproj/localization.strings
# 替换应用 Logo,根据具体需要您还可以替换 easyVideo/easyVideo/Assets.xcassets/ 下的更多其它图片文件
cp -a ./AppIcon.appiconset ../easyVideo/easyVideo/Assets.xcassets/
# 替换 版本号\Bundle ID\Bundle Name 等信息
export BUNDLE_IDENTIFIER="com.yourcompany.greatapp"
export PRODUCT_NAME="GreatApp"
BUILD_NUMBER=1
RELEASE_NUM=1.0
export VERSION=${RELEASE_NUM}.${BUILD_NUMBER}
cd ../easyVideo/
xcrun agvtool new-version ${VERSION}
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${VERSION}" ./easyVideo/Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier ${BUNDLE_IDENTIFIER}" ./easyVideo/Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleName ${PRODUCT_NAME}" ./easyVideo/Info.plist
替换完成后,使用 xcode 或 xcodebuild 重新构建工程,即可得到定制化版的客户端应用。
开发入门
初始化 SDK
使用 EVSDK 时,需要在工程中做如下配置:
文件 | 描述 |
---|---|
添加SDK库⽂件evsdk.frameworks | 示例代码⽬录/easyVideo/evsdk.framework |
添加rootca.pem文件 | 将⽂件拷⻉到工程目录下边,设置给 SDK |
在程序 AppDelegate 中初始化 SDK
#import "evsdk/IEVEngineObj.h"
@interface AppDelegate ()
{
IEVEngineObj *evengine;
}
@property (nonatomic, strong) IEVEngineObj *evengine;
@end
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
//INIT SDK
evengine = [[IEVEngineObj alloc] init];
//将sdk配置文件设置一个路径,示例代码路径为/Documents/Log/config
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *logDirectory = [[paths objectAtIndex:0]stringByAppendingPathComponent:@"Log"];
[evengine initialize:logDirectory filename:@"config"];
//设置最大视频窗口数量
[evengine setMaxRecvVideo:9];
//设置rootca.pem文件
[evengine setRootCA:@"rootca.pem的路径"];
}
设备设置
SDK 提供方法来让用户选择自己的设备,具体如下
typedef NS_ENUM (NSUInteger, EVDeviceType) {
EVDeviceAudioCapture = 0,//麦克风
EVDeviceAudioPlayback = 1,//扬声器
EVDeviceVideoCapture = 2//摄像头
};
/** 相关API如下 */
//获取某种类型的所有设备
- (NSArray<EVDevice *> * _Nonnull) getDevices:(EVDeviceType)type;
//获取当前选择的设备
- (EVDevice * _Nonnull) getDevice:(EVDeviceType)type;
//将某一个设备设置给SDK
- (void) setDevice:(EVDeviceType)type withId:(unsigned int)id;
//示例代码
NSArray *devices = [evengine getDevices:EVDeviceAudioCapture];
EVDevice *device = [evengine getDevice:EVDeviceAudioCapture];
[evengine setDevice:EVDeviceVideoCapture withId:device.id];
日志设置
EVSDK 会持续收集日志,打开日志收集需要做以下设置
/**
用于设置sdk日志相关
@param level 日志等级
@param log_path 日志存放位置
@param log_file_name 日志名称
@param max_file_size 日志大小
*/
- (void) setLog:(EVLogLevel)level path:(NSString *_Nonnull)log_path file:(NSString *_Nullable)log_file_name size:(unsigned int)max_file_size;
//示例代码,示例代码日志储存路径为/Documents/Log/evsdk
[evengine setLog:EVLogLevelMessage path:logDirectory file:@"evsdk" size:20*1024*1024];
//开启日志
[evengine enableLog:YES];
设置呼叫带宽
/**
设置呼叫带宽
@param kbps 带宽大小
@return 返回设置结果
*/
- (int) enablePreview:(BOOL)enable;
//示例代码设置2M带宽
[evengine setBandwidth:2048];
登录
匿名方式入会
用户匿名方式入会的时候会执行:定位->匿名登录->注册视频服务->呼叫 (其中匿名登录以及注册视频服务均由SDK 处理)
- 定位服务、匿名登录、注册视频服务统一都由SDK处理只需要调用以下 API
/**
用户执行匿名登录入会
@param location_server 定位服务器
@param port 端口号
@param conference_number 会议号码
@param display_name 用户在会议中的名称
@param password 会议密码
@return 返回 SDK 处理结果,UI一般可忽略
*/
- (int) joinConferenceWithLocation:(NSString *_Nonnull)location_server port:(unsigned int)port conference_number:(NSString *_Nonnull)conference_number display_name:(NSString *_Nonnull)display_name password:(NSString *_Nonnull)password;
//示例代码
[evengine joinConferenceWithLocation:anonymousDic[@"server"] port:[anonymousDic[@"port"] intValue] conference_number:anonymousDic[@"confId"] display_name:anonymousDic[@"disName"] password:anonymousDic[@"password"]];
- 入会
当调用了匿名登录的 API 后,UI 会收到 SDK 回调:入会成功、入会失败。需要做出处理
//定位或者匿名登录错误会回调
- (void)onError:(EVError *_Nonnull)err;
//匿名登录成功会回调
- (void)onLoginSucceed:(EVUserInfo *_Nonnull)user;
//入会失败会回调
- (void)onCallEnd:(EVCallInfo * _Nonnull)info;
//入会成功会回调
- (void)onCallConnected:(EVCallInfo * _Nonnull)info;
用户正常登录
用户正常登录会执行:定位->登录->注册视频服务(其中注册视频服务由 SDK 处理)
1.定位
/**
用户定位登录(包含等位跟登录)
@param location_server 定位服务器
@param port 端口号
@param username 用户名
@param password 密码
@return 返回API结果UI可忽略
*/
- (int) loginWithLocation:(NSString *_Nonnull)location_server port:(unsigned int)port name:(NSString *_Nonnull)username password:(NSString *_Nonnull)password;
//示例代码
[evengine loginWithLocation:@"服务器地址" port:@"端口号" name:@"用户名" password:@"密码"];
/** 登录后会收到SDK以下回调 */
//定位或者登录错误会回调
- (void)onError:(EVError *_Nonnull)err;
//登录成功会回调
- (void)onLoginSucceed:(EVUserInfo *_Nonnull)user;
窗口设置
EVSDK视频窗口分为三类 1. 远端窗口 2. 本地窗口 3. 内容窗口(双流、白板)
//示例代码里 最大窗口数设置了9个
[evengine setMaxRecvVideo:9];
1.远端窗口设置
/**
设置远端窗口
@param id 远端窗口数组
@param size 远端窗口数量
@return 返回结果(UI可以忽视,不作处理)
*/
- (int) setRemoteVideoWindow:(void *_Nullable[_Nonnull])id andSize:(unsigned int)size;
//示例代码(remoteArr 里的元素为NSView对象)
void * remoteArr[9];
[evengine setRemoteVideoWindow:remoteArr andSize:9];
2.本地窗口设置
/**
设置本地窗口
@param id 本地窗口对象
@return 返回结果(UI可以忽视,不作处理)
*/
- (int) setLocalVideoWindow:(void *_Nullable)id;
//示例代码(本地窗口为NSView对象)
[evengine setLocalVideoWindow:(__bridge void *)(locaVideoController.videoView)];
3.内容窗口设置
/**
设置内容窗口
@param id 内容窗口对象
@return 返回结果(UI可以忽视,不作处理)
*/
- (int) setRemoteContentWindow:(void *_Nullable)id;
//示例代码(内容窗口为NSView对象)
[evengine setRemoteContentWindow:(__bridge void *)(contentVideoController.videoView)];
4.分享窗口设置
//设置窗口ID mode = EVContentFullMode
//@property (readonly, copy) NSDictionary<NSDeviceDescriptionKey, id> *deviceDescription;
- (int) setLocalContentWindow:(void *_Nullable)id mode:(EVContentMode)mode;
实现视频通话
视频通话主要分为两种,一种是匿名入会(参考登录模块的匿名登录入会),一种是用户登录后入会
- 设置用户入会后的头像以及视频背景图片(关闭摄像头所展示的图片)
/**
设置会议中用户的头像以及背景图片
@param background_file_path 背景图片
@param user_image_path 用户图片
@return UI可不作处理
*/
- (int) setUserImage:(NSString *_Nonnull)background_file_path filename:(NSString *_Nullable)user_image_path;
//示例
NSString *downloadimagepath = @"头像图片地址";
[evengine setUserImage:@"背景图片" filename:downloadimagepath];
- 用户登录后主动入会
/// 用户加入会议
/// @param conference_number 会议号码
/// @param display_name 会议中的名字
/// @param password 会议密码
/// @param type 会议类型
- (int) joinConference:(NSString *_Nonnull)conference_number display_name:(NSString *_Nonnull)display_name password:(NSString *_Nonnull)password svcCallType:(EVSvcCallType)type;
//示例 注:会议如果没有密码可以不用给SDK传值,不传display_name则SDK会取用户名称当作会议名称
[evengine joinConference:@"会议号码" display_name:@"会议中显示的名称" password:@"会议密码" svcCallType:EVSvcCallP2P];
- 当调用了入会的 API 后,UI 会收到 SDK 回调:入会成功、入会失败。需要做出处理
//入会失败会回调
- (void)onCallEnd:(EVCallInfo * _Nonnull)info;
//入会成功会回调
- (void)onCallConnected:(EVCallInfo * _Nonnull)info;
主讲视图和画廊视图
- 主讲视图
设置主讲视图模式
/**
设置视频模式(主讲模式、画廊模式)
@param layout EVLayoutRequest对象
@return 返回结果(UI可不作处理)
*/
- (int) setLayout:(EVLayoutRequest *_Nonnull)layout;
//示例代码里主讲视图模式下 主视频窗口可以显示为1x5的窗口模式
EVLayoutRequest *layout = [[EVLayoutRequest alloc] init];
layout.page = EVLayoutCurrentPage;
layout.mode = EVLayoutSpeakerMode;
layout.max_type = EVLayoutType_5_4T_1B;
EVVideoSize vsize;
vsize.width = 1280;
vsize.height = 720;
layout.max_resolution = vsize;
[evengine setLayout:layout];
- 画廊视图
设置画廊视图模式
/**
设置视频模式(主讲模式、画廊模式)
@param layout EVLayoutRequest对象
@return 返回结果(UI可不作处理)
*/
- (int) setLayout:(EVLayoutRequest *_Nonnull)layout;
//示例代码里画廊视图模式下 主视频窗口可以显示为1x1、1x2、2x2、2x3、3x3的窗口模式(可根据需要调整窗口位置)
EVLayoutRequest *layout = [[EVLayoutRequest alloc] init];
layout.page = EVLayoutCurrentPage;
layout.mode = EVLayoutGalleryMode;
layout.max_type = EVLayoutType_9;
EVVideoSize vsize;
vsize.width = 1280;
vsize.height = 720;
layout.max_resolution = vsize;
[evengine setLayout:layout];
静音和解除静音
执行本地麦克风开启或者关闭
/**
是否启用麦克风
@param enable YES为开启NO为关闭
@return 返回结果可忽视
*/
- (int) enableMic:(BOOL)enable;
//示例代码
1.关闭麦克风
[evengine enableMic:NO];
2.开启麦克风
[evengine enableMic:YES];
申请举手发言
用户被管理员禁言后可以调用此API申请发言
/// 申请举手发言
/// @param val YES
- (int) requestRemoteUnmute:(BOOL)val;
查看当前麦克风状态
- (BOOL) micEnabled;
查看当前摄像头状态
- (BOOL) cameraEnabled;
是否打开高帧率
- (BOOL) highFPSEnabled;
获取当前用户的displayName
/// 获取当前用户displayname
- (NSString * _Nonnull) getDisplayName;
是否打开1080P
- (int) enableHD:(BOOL)enable;
进入语音或者视频模式
/// 进入语音或者视频h模式
/// @param active 0为语音 3为视频
- (int) setVideoActive:(int)active;
发送双流
- (int) sendContent;
发送白板
- (int) sendWhiteBoard;
停止双流
- (int) stopContent;
关闭或打开本地视频
执行本地摄像头开启或者关闭
/**
是否启用摄像头
@param enable YES为开启NO为关闭
@return 返回结果可忽视
*/
- (int) enableCamera:(BOOL)enable;
//示例代码
1.关闭摄像头
[evengine enableCamera:NO];
2.开启摄像头
[evengine enableCamera:YES];
修改会中名字
/// 修改会中名字
/// @param display_name 会中名字
- (int) setInConfDisplayName:(NSString *_Nonnull)display_name;
接收和显示共享内容
当为 EVSDK 设置了内容窗口的时候,收到共享或者共享结束 SDK 都会通过回调的形式告诉终端
/**
接收到内容分享或者内容分享结束的回调
@param info EVContentInfo对象
*/
- (void)onContent:(EVContentInfo * _Nonnull)info;
//示例代码
- (void)onContent:(EVContentInfo * _Nonnull)info
{
dispatch_async(dispatch_get_main_queue(), ^{
if (info.type == EVStreamContent || info.type == EVStreamWhiteBoard) {
if (info.enabled) {
//收到分享(如果设置了内容窗口那么应该在此处显示出你的内容窗口,如果没有设置内容窗口SDK将会弹出一个窗口来显示分享内容)
}else{
//分享结束(应该在此处隐藏或者关闭你的分享窗口)
}
}
});
}
结束呼叫
在需要结束呼叫的时候调用 SDK 的离会 API
- (int) leaveConference;
//示例代码
[evengine leaveConference];
//退出成功后,会收到sdk的回调
- (void)onCallEnd:(EVCallInfo * _Nonnull)info;
P2P呼叫相关内容
P2P主动呼叫
/// P2P主动呼叫
/// @param conference_number 需要呼叫人的UserId
/// @param display_name 自己的名字
/// @param password 密码设为无
/// @param type EVSvcCallP2P
- (int) joinConference:(NSString *_Nonnull)conference_number display_name:(NSString *_Nonnull)display_name password:(NSString *_Nonnull)password svcCallType:(EVSvcCallType)type;
//示例代码
[appDelegate.evengine joinConference:userId display_name:[appDelegate.evengine getUserInfo].displayName password:@"" svcCallType:EVSvcCallP2P];
接收到P2P呼叫请求
/// 收到邀请
/// @param info 会议详情
- (void)onJoinConferenceIndication:(EVCallInfo *_Nonnull)info;
__attribute__((visibility("default"))) @interface EVCallInfo : NSObject
@property (assign, nonatomic) BOOL isAudioOnly;
@property (assign, nonatomic) BOOL contentEnabled;
@property (copy, nonatomic) NSString *_Nonnull peer;//邀请人名字
@property (copy, nonatomic) NSString *_Nonnull conference_number;
@property (copy, nonatomic) NSString *_Nonnull password;
@property (strong, nonatomic) EVError *_Nonnull err;
@property (assign, nonatomic) BOOL isBigConference;
@property (assign, nonatomic) BOOL isRemoteMuted;
@property (assign, nonatomic) EVSvcCallType svcCallType;//会议类型判断为P2P邀请还是普通会议
@property (assign, nonatomic) EVSvcCallAction svcCallAction;
@end
接听
//拿到会议号码去呼叫当前P2P会议
- (void)dialCall:(NSString*)strCallee withVideoEnable:(BOOL)isVideoMode WithConf:(NSString *) conf CallType:(EVSvcCallType)callType;
###挂断
- (void) acceptCall;
对方已接受P2P呼叫
- (void)onCallPeerConnected:(EVCallInfo * _Nonnull)info;
获取主叫方头像地址
- (void)onPeerImageUrl:(NSString*)imageUrl;
API 参考
以下为用户相关接口回调
onLoginSucceed
/**
登录成功回调
@param user 返回用户信息
*/
- (void)onLoginSucceed:(EVUserInfo *_Nonnull)user;
onRegister
/**
视频服务注册状态(注册状态变化的时候将会走此回调)
@param registered YES为成功 NO为失败
*/
- (void)onRegister:(BOOL)registered;
onDownloadUserImageComplete
/**
用户头像下载成功回调
@param path 保存路径
*/
- (void)onDownloadUserImageComplete:(NSString *_Nonnull)path;
onUploadUserImageComplete
/**
用户上传头像成功回调
@param path 头像路径
*/
- (void)onUploadUserImageComplete:(NSString *_Nonnull)path;
enableSecure
/**
是否启用https协议
@param enable YES为https NO为http
@return 结果返回
*/
- (int) enableSecure:(BOOL)enable;
//示例
[evengine enableSecure:YES];
encryptPassword
/**
用户登录密码加密
@param password 密码明文
@return 返回加密后的密码
*/
- (NSString * _Nonnull) encryptPassword:(NSString * _Nonnull)password;
//示例
NSString *password = [evengine encryptPassword:password];
logout
/**
用户退出
@return 返回结果
*/
- (int) logout;
//示例
[evengine logout];
downloadUserImage
/**
下载用户当前头像(需登录后调用)
@param path 指定储存地址
@return 返回结果
*/
- (int) downloadUserImage:(NSString *_Nonnull)path;
//示例
[evengine downloadUserImage:downloadimagepath];
uploadUserImage
/**
向服务器上传用户头像
@param path 上传图片地址
@return 返回结果
*/
- (int) uploadUserImage:(NSString *_Nonnull)path;
//示例
[evengine uploadUserImage:downloadimagepath];
changePassword
/**
修改当前用户密码
@param oldpassword 原密码
@param newpassword 新密码
@return 返回结果
*/
- (int) changePassword:(NSString *_Nonnull)oldpassword newpassword:(NSString *_Nonnull)newpassword;
//示例(密码需要使用SDK方法加密)
int state = [evengine changePassword:[evengine encryptPassword:oldpwStr] newpassword:[evengine encryptPassword:newpwStr]];
if (state == EVOK) {
//修改成功
}
changeDisplayName
/**
修改当前用户名称
@param display_name 用户名称
@return 返回结果
*/
- (int) changeDisplayName:(NSString *_Nonnull)display_name;
//示例
int state = [evengine changeDisplayName:displayNameStr];
if (state == EVOK) {
//修改成功
}
getUserInfo
/**
获取当前用户信息
@return 返回当前用户信息
*/
- (EVUserInfo *_Nullable) getUserInfo;
//示例
EVUserInfo *userInfo = [evengine getUserInfo];
__attribute__((visibility("default"))) @interface EVUserInfo : NSObject
@property (copy, nonatomic) NSString *_Nonnull username;
@property (copy, nonatomic) NSString *_Nonnull displayName;
@property (copy, nonatomic) NSString *_Nonnull org;
@property (copy, nonatomic) NSString *_Nonnull email;
@property (copy, nonatomic) NSString *_Nonnull cellphone;
@property (copy, nonatomic) NSString *_Nonnull telephone;
@property (assign, nonatomic) BOOL everChangedPasswd;
@property (copy, nonatomic) NSString *_Nonnull dept;
@property (copy, nonatomic) NSString *_Nonnull customizedH5UrlPrefix;
@property (copy, nonatomic) NSString *_Nonnull token;
@end
以下为呼叫相关接口及回调
onCallConnected
/**
入会成功之后走此回调
@param info 当前呼叫信息
*/
- (void)onCallConnected:(EVCallInfo * _Nonnull)info;
onCallEnd
/**
会议结束后走此回调
@param info 会议信息
*/
- (void)onCallEnd:(EVCallInfo * _Nonnull)info;
onContent
/**
主会场模式开启关闭通知(在主会场模式下,将只能收到一路远端视频)
@param info 主会场信息
*/
- (void)onContent:(EVContentInfo * _Nonnull)info;
//示例代码
- (void)onContent:(EVContentInfo * _Nonnull)info
{
dispatch_async(dispatch_get_main_queue(), ^{
if (info.type == EVStreamContent || info.type == EVStreamWhiteBoard) {
if (info.enabled) {
//当前会议为主会场模式
}else{
//当前会议为讨论模式
}
}
});
}
onLayoutSiteIndication
/**
收到禁言或者解除禁言的通知
@param site 发起操作的用户
*/
- (void)onLayoutSiteIndication:(EVSite *_Nonnull)site;
//示例代码
- (void)onLayoutSiteIndication:(EVSite *_Nonnull)site
{
dispatch_async(dispatch_get_main_queue(), ^{
//is_local为YES,指的是当前自己操作的麦克风,否则为当前会议中的其他用户操作的麦克风
if (site.is_local) {
if (site.remote_muted) {
//被禁言
}else{
//解除禁言
}
}else {
if (site.mic_muted) {
//被禁言
}else {
//解除禁言
}
}
});
}
onLayoutSpeakerIndication
/**
当前会议的发言者
@param speaker 发言人信息
*/
- (void)onLayoutSpeakerIndication:(EVLayoutSpeakerIndication *_Nonnull)speaker;
//示例代码
- (void)onLayoutSpeakerIndication:(EVLayoutSpeakerIndication *_Nonnull)speaker
{
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i<self->remoteList.count; i++)
{
self->remotVideoController = self->remoteList[i];
if ([self->remotVideoController.userName.stringValue isEqualToString:speaker.speaker_name])
{
//当前这个窗口的人在发言
}else{
//其他窗口的人没有发言
}
}
});
}
onJoinConferenceIndication
/**
收到会议邀请的通知
@param info 邀请会议的信息
*/
- (void)onJoinConferenceIndication:(EVCallInfo *_Nonnull)info;
__attribute__((visibility("default"))) @interface EVCallInfo : NSObject
@property (assign, nonatomic) BOOL isAudioOnly;
@property (assign, nonatomic) BOOL contentEnabled;
@property (copy, nonatomic) NSString *_Nonnull peer;
@property (copy, nonatomic) NSString *_Nonnull conference_number;
@property (copy, nonatomic) NSString *_Nonnull password;
@property (strong, nonatomic) EVError *_Nonnull err;
@end
onRecordingIndication
/**
是否有录制终端参与
@param info 录制终端信息
*/
- (void)onRecordingIndication:(EVRecordingInfo *_Nonnull)info;
//录制相关枚举
typedef NS_ENUM (NSUInteger, EVRecordingState) {
EVRecordingStateNone = 0,//没有录制
EVRecordingStateOn = 1,//正在录制
EVRecordingStatePause = 2//暂停录制
};
onMessageOverlay
/**
会议字幕相关通知
@param msg 字幕信息
*/
- (void)onMessageOverlay:(EVMessageOverlay *_Nonnull)msg;
__attribute__((visibility("default"))) @interface EVMessageOverlay : NSObject
@property (assign, nonatomic) BOOL enable;//是否开启字幕
@property (copy, nonatomic) NSString *_Nonnull content;//字幕内容
@property (assign, nonatomic) int displayRepetitions;//字幕重复次数
@property (assign, nonatomic) int displaySpeed;//字幕速度
@property (assign, nonatomic) int verticalBorder;//字幕垂直边界
@property (assign, nonatomic) int transparency;//字幕透明度
@property (assign, nonatomic) int fontSize;//字体大小
@property (copy, nonatomic) NSString *_Nonnull foregroundColor;//字体颜色
@property (copy, nonatomic) NSString *_Nonnull backgroundColor;//背景颜色
@end
onParticipant
/**
获取当前参与会议人数
@param number 当前参与人数
*/
- (void)onParticipant:(int)number;
当前会议禁止解除静音
//warn = EVWarnUnmuteAudioNotAllowed
- (void)onWarn:(EVWarn *)warn;
主持人解除当前终端静音时收到的回调
//warn = EVWarnUnmuteAudioIndication
- (void)onWarn:(EVWarn *)warn;
//示例代码
[appDelegate.evengine enableMic:NO];//不同意解除
[appDelegate.evengine enableMic:YES];//同意解除
远端静音提示
当会议中发生远端对该终端进行静音或者解除静音时,SDK会该回调事件
/**
远端静音提示
@param int, 当取值为0时,表示远端静音,否则为远端解除静音
*/
- (void)onMicMutedShow:(int)mic_muted;
其他接口及回调
onError
/** SDK错误回调需要查看错误类型做出相应处理 */
- (void)onError:(EVError *_Nonnull)err;
setDelegate
/**
设置SDK代理
@param aDelegate SDK代理
*/
- (void) setDelegate:(id<EVEngineDelegate>_Nonnull)aDelegate;
//示例代码
[evengine setDelegate:self];
enableHighFPS
/**
设置高帧率
@param enable YES为高帧率 NO为相反
@return 返回结果
*/
- (int) enableHighFPS:(BOOL)enable;
//示例
[evengine enableHighFPS:YES];
getNetworkQuality
/**
获取当前信号强度
@return 返回信号数值
*/
- (float) getNetworkQuality;
//示例
float signalValue = [evengine getNetworkQuality];
错误码以及枚举类型
/** 信号统计相关枚举 */
typedef NS_ENUM (NSUInteger, EVStreamType) {
EVStreamAudio = 0,//音频流
EVStreamVideo = 1,//视频流
EVStreamContent = 2,//分享内容
EVStreamWhiteBoard = 3//白板
};
typedef NS_ENUM (NSUInteger, EVStreamDir) {
EVStreamUpload = 0,//上传
EVStreamDownload = 1,//下载
};
/** 日志设置 */
typedef NS_ENUM (NSUInteger, EVLogLevel) {
EVLogLevelDebug = 0,
EVLogLevelMessage = 1,
EVLogLevelWARNING = 2,
EVLogLevelError = 3,
EVLogLevelFatal = 4
};
- (void) setLog:(EVLogLevel)level path:(NSString *_Nonnull)log_path file:(NSString *_Nullable)log_file_name size:(unsigned int)max_file_size;
/** SDK返回错误信息类型 */
typedef NS_ENUM (NSUInteger, EVErrorType) {
EVErrorTypeSdk = 0,//SDK错误
EVErrorTypeServer = 1,//服务器错误
EVErrorTypeLocate = 2,//定位错误
EVErrorTypeCall = 3,//呼叫错误
EVErrorTypeUnknown = 4//未知错误
};
//如果接收到SDK的错误回调,可以根据EVErrorType定位错误类型
- (void)onError:(EVError *_Nonnull)err;
__attribute__((visibility("default"))) @interface EVError : NSObject
@property (assign, nonatomic) EVErrorType type;
@property (assign, nonatomic) int code;
@property (copy, nonatomic) NSString *_Nonnull msg;
@end
//SDK 错误枚举
typedef NS_ENUM (NSUInteger, EVSdkError) {
EVOK = 0,
EVNG = 1,
EVUninitialized = 2,
EVBadFormat = 3,
EVNotInConf = 4,
EVBadParam = 5,
EVRegisterFailed = 6,
EVInternalError = 7
};
//服务器错误枚举
typedef NS_ENUM (NSUInteger, EVServerError) {
EVServerApiVersionNotSupported = 1000,
EVServerInvalidToken = 1001,
EVServerInvalidParameter = 1002,
EVServerInvalidDevicesn = 1003,
EVServerInvalidMediaType = 1004,
EVServerPermissionDenied = 1005,
EVServerWrongFieldName = 1006,
EVServerInternalSystemError = 1007,
EVServerOperationFailed = 1008,
EVServerGetFailed = 1009,
EVServerNotSupported = 1010,
EVServerRedisLockTimeout = 1011,
EVServerInvalidUserNamePassword = 1100,
EVServerLoginFailedMoreThan5Times = 1101,
EVServerAccountTemporarilyLocked = 1102,
EVServerAccountDisabled = 1103,
EVServerNoUsername = 1104,
EVServerEmailMismatch = 1105,
EVServerCompanyAdministratorNotInAnyCompany = 1106,
EVServerFileUploadFailed = 1200,
EVServerInvalidLicense = 1201,
EVServerInvalidImportUserFile = 1202,
EVServerInvalidTimeServiceAddress = 1300,
EVServerFailedUpdateSystemProperties = 1301,
EVServerConfNotExists = 1400,
EVServerNumericidConflicts = 1401,
EVServerConfUpdatingInProgress = 1402,
EVServerConfDeletingInProgress = 1403,
EVServerConfTerminatingInProgress = 1404,
EVServerConfLaunchingInProgress = 1405,
EVServerConfNotInApprovedStatus = 1406,
EVServerConfNumericidOngoing = 1407,
EVServerConfNotApprovedOrOngoing = 1409,
EVServerParticipantNotExistsInConf = 1410,
EVServerNumericidAlreadyInUse = 1412,
EVServerInvalidConfTime = 1415,
EVServerInvalidConfId = 1418,
EVServerNotFoundSuitableMru = 1421,
EVServerNotFoundSuitableGateway = 1422,
EVServerFailedToConnectMru = 1424,
EVServerNotAllowDuplicatedName = 1427,
EVServerNotFoundConfInRedis = 1430,
EVServerNotInLecturerMode = 1431,
EVServerFailedToMuteAllParticipants = 1433,
EVServerFailedToConnectParticipant = 1436,
EVServerFailedToDisconnectParticipant = 1439,
EVServerFailedToChangeLayout = 1442,
EVServerFailedToSetSubtitle = 1445,
EVServerFailedToMuteParticipantAudio = 1448,
EVServerFailedToDeleteParticipant = 1451,
EVServerFailedToInviteAvcEndpoint = 1454,
EVServerFailedToInviteSvcEndpoints = 1455,
EVServerConfRoomCompletelyFull = 1456,
EVServerTimeoutToGenerateNumericid = 1457,
EVServerNotFoundProfileNamedSvc = 1460,
EVServerFailedToProlongConf = 1463,
EVServerInvalidMeetingControlRequest = 1500,
EVServerNameInUse = 1600,
EVServerEmptyEndpointName = 1601,
EVServerEmptyEndpointCallMode = 1602,
EVServerEmptyEndpointSipUsername = 1603,
EVServerEmptyEndpointSipPassword = 1604,
EVServerEmptyEndpointAddress = 1605,
EVServerInvalidSipUsername = 1606,
EVServerInvalidIpAddress = 1607,
EVServerEndpointNotExist = 1608,
EVServerE164InUse = 1609,
EVServerEndpointDeviceSnExist = 1610,
EVServerSipUsernameRegistered = 1611,
EVServerEndpointE164Invalid = 1612,
EVServerNotFoundEndpointDeviceSn = 1613,
EVServerNotFoundEndpointProvisionTemplate = 1614,
EVServerDeviceSnExists = 1615,
EVServerCanNotDeleteUserInReservedMeeting = 1700,
EVServerEmptyUserPassword = 1701,
EVServerEmptyUsername = 1702,
EVServerEmptyUserDisplayName = 1703,
EVServerInvalidUserEmail = 1704,
EVServerInvalidCellphoneNumber = 1705,
EVServerOriginalPasswordWrong = 1706,
EVServerDuplicateEmailName = 1707,
EVServerDuplicateCellphoneNumber = 1708,
EVServerDuplicateUsername = 1709,
EVServerInvalidConfRoomMaxCapacity = 1710,
EVServerShouldAssignDepartmentToDepartmentAdministrator = 1711,
EVServerEmptyUserEmail = 1712,
EVServerEmptyUserCellphoneNumber = 1713,
EVServerNotOrganizationAdministrator = 1714,
EVServerCompanyNotExist = 1800,
EVServerShortNameOfCompanyUsed = 1801,
EVServerFullNameOfCompanyUsed = 1802,
EVServerCompanyNotEmpty = 1803,
EVServerEmptyCompanyShortName = 1804,
EVServerAgentInUse = 1900,
EVServerShortNameInUse = 1901,
EVServerFullNameInUse = 1902,
EVServerAgentNotExist = 1903,
EVServerAgentNotEmpty = 1904,
EVServerConfRoomExpired = 2000,
EVServerNotActived = 2001,
EVServerNotFoundSuitableRoom = 2003,
EVServerNotFoundTemplateOrRoom = 2005,
EVServerConfRoomInUse = 2006,
EVServerConfRoomNumberInUse = 2009,
EVServerConfRoomCapacityExceedsLimit = 2012,
EVServerInvalidConfRoomCapacity = 2015,//PasswordRequired
EVServerInvalidConfRoomNumber = 2018,
EVServerRoomNotExists = 2021,
EvServerRoomNotAllowAnonymousCall = 2031,
EvServerRoomOnlyAllowOwnerActive = 2033,
EvServerTrialPeriodExpired = 2035,
EVServerCanNotDeleteDepartmentWithSubordinateDepartment = 2100,
EVServerCanNotDeleteDepartmentWithUsersOrEndpoints = 2101,
EVServerInvalidAcsConfiguration = 2200
};
//定位错误枚举
typedef NS_ENUM (NSUInteger, EVLocateError) {
EVLocateFailedToReadBody = 10000,
EVLocateFailedToParseBody = 10001,
EVLocateLocationTimeout = 10002,
EVLocateErrorInfoGeneral = 10003,
EVLocateErrorInfoBadFormat = 10004,
EVLocateUnexpected = 10005,
EVLocateFailedToLocateClient = 10006,
EVLocateFailedToLocateZone = 10007,
EVLocateNoLocationDomain = 10008,
EVLocateErrorLocationRequest = 10009
};
//呼叫相关错误枚举
typedef NS_ENUM (NSUInteger, EVCallError) {
EVCallInvalidNumericid = 1001,
EVCallInvalidUsername = 1003,
EVCallInvalidUserid = 1005,
EVCallInvalidDeviceid = 1007,
EVCallInvalidEndpoint = 1009,
EVCallServerUnlicensed = 2001,
EVCallNotFoundSuitableMru = 2003,
EVCallNeitherTemplateNorOngoingNorBindedRoom = 2005,
EVCallLockTimeout = 2007,
EVCallTemplateConfWithoutConfroom = 2009,
EVCallRoomExpired = 2011,
EVCallInvalidPassword = 2015,
EVCallNoTimeSpaceToActivateRoom = 2017,
EVCallConfPortCountUsedUp = 2023,
EVCallOrgPortCountUsedUp = 2024,
EVCallHaishenPortCountUsedUp = 2025,
EVCallHaishenGatewayAudioPortCountUsedUp = 2027,
EVCallHaishenGatewayVideoPortCountUsedUp = 2029,
EVCallOnlyRoomOwnerCanActivateRoom = 2031,
EVCallNotAllowAnonymousParty = 2033,
EVCallTrialOrgExpired = 2035
};
//视频模式枚举
typedef NS_ENUM (NSUInteger, EVLayoutMode) {
EVLayoutAutoMode = 0,
EVLayoutGalleryMode = 1,
EVLayoutSpeakerMode = 2,
EVLayoutSpecifiedMode = 3
};