版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.06.10 |
前言
很多app种都集成环信做第三方信息通讯工具,这里我们就看一下环信的主要功能和集成方法。先给出环信3.0的地址。
感兴趣的可以参考:
1. 环信ios客户端的集成(一)
2. 环信ios客户端的集成(二)
3. 环信ios客户端的集成(三)
4. 环信ios客户端的集成(四)
5. 环信ios客户端的集成(五)
6. 环信ios客户端的集成(六)
7. 环信ios客户端的集成(七)
8. 环信ios客户端的集成(八)
这一篇主要说一下环信的 实时通话。
一、实时通话的数据流量
环信实时通话分为视频通话和语音通话,SDK 提供简单的 API,方便开发者简单的接入实时通话功能。
实时语音和实时视频通话的数据流量如下:
- 实时语音:双向 170k bytes/minute
- 实时视频:双向 2.5M~3M bytes/minute
二、配置工程
1. 在项目中导入库
Hyphenate.framework //包含实时音视频的库
AVFoundation.framework
2. 在项目中导入头文件
#import
3. 配置属性
进行音视频之前,设置全局的音视频属性,具体属性有哪些请查看头文件 EMCallOptions
EMCallOptions *options = [[EMClient sharedClient].callManager getCallOptions];
//当对方不在线时,是否给对方发送离线消息和推送,并等待对方回应
options.isSendPushIfOffline = NO;
[[EMClient sharedClient].callManager setCallOptions:options];
具体实现可以参考 Demo: DemoCallManager 和 EMCallViewController
三、发起实时通话
用户可以调用发起语音或者视频 API 向在线用户发起实时通话。
/*!
* 发起实时会话
*
* @param aType 通话类型
* @param aRemoteName 被呼叫的用户(不能与自己通话)
* @param aExt 通话扩展信息,会传给被呼叫方
* @param aCompletionBlock 完成的回调
*/
- (void)startCall:(EMCallType)aType
remoteName:(NSString *)aRemoteName
ext:(NSString *)aExt
completion:(void (^)(EMCallSession *aCallSession, EMError *aError))aCompletionBlock;
示例代码:创建视频通话
void (^completionBlock)(EMCallSession *, EMError *) = ^(EMCallSession *aCallSession, EMError *aError){
//创建通话实例是否成功
//TODO: code
};
[[EMClient sharedClient].callManager startCall:EMCallTypeVideo remoteName:aUsername ext:nil completion:^(EMCallSession *aCallSession, EMError *aError) {
completionBlock(aCallSession, aError);
}];
四、被叫方同意实时通话
接收到通话时调用此 API 同意实时通话。
/*!
* 接收方同意通话请求
*
* @param aCallId 通话ID
*
* @result 错误信息
*/
- (EMError *)answerIncomingCall:(NSString *)aCallId;
//调用:
//EMError *error = nil;
//error = [[EMClient sharedClient].callManager answerIncomingCall:@"sessionId"];
五、结束实时通话
根据不同场景可以选择结束会话的原因。
例如:拒接选择 EMCallEndReasonDecline,主动挂断选择 EMCallEndReasonHangup。
typedef enum{
EMCallEndReasonHangup = 0, /*! 对方挂断 */
EMCallEndReasonNoResponse, /*! 对方没有响应 */
EMCallEndReasonDecline, /*! 对方拒接 */
EMCallEndReasonBusy, /*! 对方占线 */
EMCallEndReasonFailed, /*! 失败 */
EMCallEndReasonUnsupported, /*! 功能不支持 */
}EMCallEndReason;
/*!
* 结束通话
*
* @param aCallId 通话的ID
* @param aReason 结束原因
*
* @result 错误
*/
- (EMError *)endCall:(NSString *)aCallId
reason:(EMCallEndReason)aReason;
//调用:
//[[EMClient sharedClient].callManager endCall:@"sessionId" reason:aReason];
六、创建通话页面
SDK提供了用于显示本地视频的页面类EMCallLocalView,显示对方视频的页面类EMCallRemoteView,建议在同意接通视频通话之后再初始化 EMCallRemoteView页面。
//前提:EMCallSession *callSession 存在
CGFloat width = 80;
CGFloat height = self.view.frame.size.height / self.view.frame.size.width * width;
callSession.localVideoView = [[EMCallLocalView alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 90, CGRectGetMaxY(_statusLabel.frame), width, height)];
[self.view addSubview:callSession.localVideoView];
//同意接听视频通话之后
callSession.remoteVideoView = [[EMCallRemoteView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
//设置视频页面缩放方式
callSession.remoteVideoView.scaleMode = EMCallViewScaleModeAspectFill;
[self.view addSubview:_callSession.remoteVideoView];
七、扩展功能之 录制和截屏
EMCallSession中录制及截屏接口已废弃,该功能作为音视频的插件之一单独打成了静态库。录制和截屏都必须在通话已经开始进行之后再调用。
点击下载静态库
1. 头文件
EMAVPluginRecorder.h
2. 库
libbz2.tbd
libHyphenatePluginRecorder.a
libffmpeg-ios-full.a
3. 使用教程
必须在开始通话之前调用[EMAVPluginRecorder initGlobal],该方法为全局方法,只需要调用一次即可
示例代码:开始录制(已经开始通话之后再调用)
NSString *recordPath = NSHomeDirectory();
recordPath = [NSString stringWithFormat:@"%@/Library/appdata/chatbuffer", recordPath];
NSFileManager *fm = [NSFileManager defaultManager];
if(![fm fileExistsAtPath:recordPath]) {
[fm createDirectoryAtPath:recordPath withIntermediateDirectories:YES attributes:nil error:nil];
}
[EMAVPluginRecorder startVideoRecord:recordPath];
示例代码:停止录制
NSString *filePath = [EMAVPluginRecorder stopVideoRecord];
示例代码:截屏(已经开始通话之后再调用)
NSString *imgPath = NSHomeDirectory();
imgPath = [NSString stringWithFormat:@"%@/Library/appdata/chatbuffer/img.jpeg", imgPath];
[EMAVPluginRecorder takeRemotePicture:imgPath];
八、实时通话相关 API
暂停恢复实时通话的数据传输相关 API。
/*!
* 暂停语音数据传输
*
* @result 错误
*/
- (EMError *)pauseVoice;
/*!
* 恢复语音数据传输
*
* @result 错误
*/
- (EMError *)resumeVoice;
/*!
* 暂停视频图像数据传输
*
* @result 错误
*/
- (EMError *)pauseVideo;
/*!
* 恢复视频图像数据传输
*
* @result 错误
*/
- (EMError *)resumeVideo;
实时通话前后摄像头切换相关API
#pragma mark - Camera
/*!
* 设置使用前置摄像头还是后置摄像头,默认使用前置摄像头
*
* @param aIsFrontCamera 是否使用前置摄像头, YES使用前置, NO使用后置
*/
- (void)switchCameraPosition:(BOOL)aIsFrontCamera;
九、实时通话相关的回调
注册实时通话回调
//注册实时通话回调
[[EMClient sharedClient].callManager addDelegate:self delegateQueue:nil];
//移除实时通话回调
[[EMClient sharedClient].callManager removeDelegate:self];
相关回调说明:
/*!
* 用户A拨打用户B,用户B会收到这个回调
*
* @param aSession 会话实例
*/
- (void)callDidReceive:(EMCallSession *)aSession;
/*!
* 通话通道建立完成,用户A和用户B都会收到这个回调
*
* @param aSession 会话实例
*/
- (void)callDidConnect:(EMCallSession *)aSession;
/*!
* 用户B同意用户A拨打的通话后,用户A会收到这个回调
*
* @param aSession 会话实例
*/
- (void)callDidAccept:(EMCallSession *)aSession;
/*!
* 1. 用户A或用户B结束通话后,对方会收到该回调
* 2. 通话出现错误,双方都会收到该回调
*
* @param aSession 会话实例
* @param aReason 结束原因
* @param aError 错误
*/
- (void)callDidEnd:(EMCallSession *)aSession
reason:(EMCallEndReason)aReason
error:(EMError *)aError;
/*!
* 用户A和用户B正在通话中,用户A中断或者继续数据流传输时,用户B会收到该回调
*
* @param aSession 会话实例
* @param aType 改变类型
*/
- (void)callStateDidChange:(EMCallSession *)aSession
type:(EMCallStreamingStatus)aType;
十、弱网检测
通过回调通知应用当前实时通话网络状态。
typedef enum{
EMCallNetworkStatusNormal = 0, /*! 正常 */
EMCallNetworkStatusUnstable, /*! 不稳定 */
EMCallNetworkStatusNoData, /*! 没有数据 */
}EMCallNetworkStatus;
/*!
* 用户A和用户B正在通话中,用户A的网络状态出现不稳定,用户A会收到该回调
*
* @param aSession 会话实例
* @param aStatus 当前状态
*/
- (void)callNetworkDidChange:(EMCallSession *)aSession
status:(EMCallNetworkStatus)aStatus
十一、离线发推送
1.配置属性
EMCallOptions *options = [[EMClient sharedClient].callManager getCallOptions];
//当对方不在线时,是否给对方发送离线消息和推送,并等待对方回应
options.isSendPushIfOffline = NO;
[[EMClient sharedClient].callManager setCallOptions:options];
2.监听回调
[[EMClient sharedClient].callManager setBuilderDelegate:self];
3. 处理回调
- (void)callRemoteOffline:(NSString *)aRemoteName
{
NSString *text = [[EMClient sharedClient].callManager getCallOptions].offlineMessageText;
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:text];
NSString *fromStr = [EMClient sharedClient].currentUsername;
EMMessage *message = [[EMMessage alloc] initWithConversationID:aRemoteName from:fromStr to:aRemoteName body:body ext:@{@"em_apns_ext":@{@"em_push_title":text}}];
message.chatType = EMChatTypeChat;
[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil];
}
后记
未完,待续~~~