版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2017.06.10 |
前言
很多app種都集成環(huán)信做第三方信息通訊工具,這里我們就看一下環(huán)信的主要功能和集成方法。先給出環(huán)信3.0的地址没宾。
感興趣的可以參考:
1. 環(huán)信ios客戶端的集成(一)
2. 環(huán)信ios客戶端的集成(二)
3. 環(huán)信ios客戶端的集成(三)
4. 環(huán)信ios客戶端的集成(四)
5. 環(huán)信ios客戶端的集成(五)
6. 環(huán)信ios客戶端的集成(六)
7. 環(huán)信ios客戶端的集成(七)
8. 環(huán)信ios客戶端的集成(八)
這一篇主要說一下環(huán)信的 實(shí)時(shí)通話侠讯。
一、實(shí)時(shí)通話的數(shù)據(jù)流量
環(huán)信實(shí)時(shí)通話分為視頻通話和語音通話把介,SDK 提供簡單的 API邑退,方便開發(fā)者簡單的接入實(shí)時(shí)通話功能。
實(shí)時(shí)語音和實(shí)時(shí)視頻通話的數(shù)據(jù)流量如下:
- 實(shí)時(shí)語音:雙向 170k bytes/minute
- 實(shí)時(shí)視頻:雙向 2.5M~3M bytes/minute
二劳澄、配置工程
1. 在項(xiàng)目中導(dǎo)入庫
Hyphenate.framework //包含實(shí)時(shí)音視頻的庫
AVFoundation.framework
2. 在項(xiàng)目中導(dǎo)入頭文件
#import <Hyphenate/Hyphenate.h>
3. 配置屬性
進(jìn)行音視頻之前地技,設(shè)置全局的音視頻屬性,具體屬性有哪些請(qǐng)查看頭文件 EMCallOptions
EMCallOptions *options = [[EMClient sharedClient].callManager getCallOptions];
//當(dāng)對(duì)方不在線時(shí)秒拔,是否給對(duì)方發(fā)送離線消息和推送莫矗,并等待對(duì)方回應(yīng)
options.isSendPushIfOffline = NO;
[[EMClient sharedClient].callManager setCallOptions:options];
具體實(shí)現(xiàn)可以參考 Demo: DemoCallManager 和 EMCallViewController
三、發(fā)起實(shí)時(shí)通話
用戶可以調(diào)用發(fā)起語音或者視頻 API 向在線用戶發(fā)起實(shí)時(shí)通話砂缩。
/*!
* 發(fā)起實(shí)時(shí)會(huì)話
*
* @param aType 通話類型
* @param aRemoteName 被呼叫的用戶(不能與自己通話)
* @param aExt 通話擴(kuò)展信息作谚,會(huì)傳給被呼叫方
* @param aCompletionBlock 完成的回調(diào)
*/
- (void)startCall:(EMCallType)aType
remoteName:(NSString *)aRemoteName
ext:(NSString *)aExt
completion:(void (^)(EMCallSession *aCallSession, EMError *aError))aCompletionBlock;
示例代碼:創(chuàng)建視頻通話
void (^completionBlock)(EMCallSession *, EMError *) = ^(EMCallSession *aCallSession, EMError *aError){
//創(chuàng)建通話實(shí)例是否成功
//TODO: code
};
[[EMClient sharedClient].callManager startCall:EMCallTypeVideo remoteName:aUsername ext:nil completion:^(EMCallSession *aCallSession, EMError *aError) {
completionBlock(aCallSession, aError);
}];
四、被叫方同意實(shí)時(shí)通話
接收到通話時(shí)調(diào)用此 API 同意實(shí)時(shí)通話庵芭。
/*!
* 接收方同意通話請(qǐng)求
*
* @param aCallId 通話ID
*
* @result 錯(cuò)誤信息
*/
- (EMError *)answerIncomingCall:(NSString *)aCallId;
//調(diào)用:
//EMError *error = nil;
//error = [[EMClient sharedClient].callManager answerIncomingCall:@"sessionId"];
五妹懒、結(jié)束實(shí)時(shí)通話
根據(jù)不同場(chǎng)景可以選擇結(jié)束會(huì)話的原因。
例如:拒接選擇 EMCallEndReasonDecline双吆,主動(dòng)掛斷選擇 EMCallEndReasonHangup眨唬。
typedef enum{
EMCallEndReasonHangup = 0, /*! 對(duì)方掛斷 */
EMCallEndReasonNoResponse, /*! 對(duì)方?jīng)]有響應(yīng) */
EMCallEndReasonDecline, /*! 對(duì)方拒接 */
EMCallEndReasonBusy, /*! 對(duì)方占線 */
EMCallEndReasonFailed, /*! 失敗 */
EMCallEndReasonUnsupported, /*! 功能不支持 */
}EMCallEndReason;
/*!
* 結(jié)束通話
*
* @param aCallId 通話的ID
* @param aReason 結(jié)束原因
*
* @result 錯(cuò)誤
*/
- (EMError *)endCall:(NSString *)aCallId
reason:(EMCallEndReason)aReason;
//調(diào)用:
//[[EMClient sharedClient].callManager endCall:@"sessionId" reason:aReason];
六、創(chuàng)建通話頁面
SDK提供了用于顯示本地視頻的頁面類EMCallLocalView好乐,顯示對(duì)方視頻的頁面類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)];
//設(shè)置視頻頁面縮放方式
callSession.remoteVideoView.scaleMode = EMCallViewScaleModeAspectFill;
[self.view addSubview:_callSession.remoteVideoView];
七蔚万、擴(kuò)展功能之 錄制和截屏
??EMCallSession中錄制及截屏接口已廢棄岭妖,該功能作為音視頻的插件之一單獨(dú)打成了靜態(tài)庫。錄制和截屏都必須在通話已經(jīng)開始進(jìn)行之后再調(diào)用反璃。
點(diǎn)擊下載靜態(tài)庫
1. 頭文件
EMAVPluginRecorder.h
2. 庫
libbz2.tbd
libHyphenatePluginRecorder.a
libffmpeg-ios-full.a
3. 使用教程
必須在開始通話之前調(diào)用[EMAVPluginRecorder initGlobal]昵慌,該方法為全局方法,只需要調(diào)用一次即可
示例代碼:開始錄制(已經(jīng)開始通話之后再調(diào)用)
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];
示例代碼:截屏(已經(jīng)開始通話之后再調(diào)用)
NSString *imgPath = NSHomeDirectory();
imgPath = [NSString stringWithFormat:@"%@/Library/appdata/chatbuffer/img.jpeg", imgPath];
[EMAVPluginRecorder takeRemotePicture:imgPath];
八淮蜈、實(shí)時(shí)通話相關(guān) API
暫驼剩恢復(fù)實(shí)時(shí)通話的數(shù)據(jù)傳輸相關(guān) API。
/*!
* 暫停語音數(shù)據(jù)傳輸
*
* @result 錯(cuò)誤
*/
- (EMError *)pauseVoice;
/*!
* 恢復(fù)語音數(shù)據(jù)傳輸
*
* @result 錯(cuò)誤
*/
- (EMError *)resumeVoice;
/*!
* 暫停視頻圖像數(shù)據(jù)傳輸
*
* @result 錯(cuò)誤
*/
- (EMError *)pauseVideo;
/*!
* 恢復(fù)視頻圖像數(shù)據(jù)傳輸
*
* @result 錯(cuò)誤
*/
- (EMError *)resumeVideo;
實(shí)時(shí)通話前后攝像頭切換相關(guān)API
#pragma mark - Camera
/*!
* 設(shè)置使用前置攝像頭還是后置攝像頭,默認(rèn)使用前置攝像頭
*
* @param aIsFrontCamera 是否使用前置攝像頭, YES使用前置, NO使用后置
*/
- (void)switchCameraPosition:(BOOL)aIsFrontCamera;
九礁芦、實(shí)時(shí)通話相關(guān)的回調(diào)
注冊(cè)實(shí)時(shí)通話回調(diào)
//注冊(cè)實(shí)時(shí)通話回調(diào)
[[EMClient sharedClient].callManager addDelegate:self delegateQueue:nil];
//移除實(shí)時(shí)通話回調(diào)
[[EMClient sharedClient].callManager removeDelegate:self];
相關(guān)回調(diào)說明:
/*!
* 用戶A撥打用戶B蜻韭,用戶B會(huì)收到這個(gè)回調(diào)
*
* @param aSession 會(huì)話實(shí)例
*/
- (void)callDidReceive:(EMCallSession *)aSession;
/*!
* 通話通道建立完成悼尾,用戶A和用戶B都會(huì)收到這個(gè)回調(diào)
*
* @param aSession 會(huì)話實(shí)例
*/
- (void)callDidConnect:(EMCallSession *)aSession;
/*!
* 用戶B同意用戶A撥打的通話后,用戶A會(huì)收到這個(gè)回調(diào)
*
* @param aSession 會(huì)話實(shí)例
*/
- (void)callDidAccept:(EMCallSession *)aSession;
/*!
* 1. 用戶A或用戶B結(jié)束通話后肖方,對(duì)方會(huì)收到該回調(diào)
* 2. 通話出現(xiàn)錯(cuò)誤闺魏,雙方都會(huì)收到該回調(diào)
*
* @param aSession 會(huì)話實(shí)例
* @param aReason 結(jié)束原因
* @param aError 錯(cuò)誤
*/
- (void)callDidEnd:(EMCallSession *)aSession
reason:(EMCallEndReason)aReason
error:(EMError *)aError;
/*!
* 用戶A和用戶B正在通話中,用戶A中斷或者繼續(xù)數(shù)據(jù)流傳輸時(shí)俯画,用戶B會(huì)收到該回調(diào)
*
* @param aSession 會(huì)話實(shí)例
* @param aType 改變類型
*/
- (void)callStateDidChange:(EMCallSession *)aSession
type:(EMCallStreamingStatus)aType;
十析桥、弱網(wǎng)檢測(cè)
通過回調(diào)通知應(yīng)用當(dāng)前實(shí)時(shí)通話網(wǎng)絡(luò)狀態(tài)。
typedef enum{
EMCallNetworkStatusNormal = 0, /*! 正常 */
EMCallNetworkStatusUnstable, /*! 不穩(wěn)定 */
EMCallNetworkStatusNoData, /*! 沒有數(shù)據(jù) */
}EMCallNetworkStatus;
/*!
* 用戶A和用戶B正在通話中艰垂,用戶A的網(wǎng)絡(luò)狀態(tài)出現(xiàn)不穩(wěn)定泡仗,用戶A會(huì)收到該回調(diào)
*
* @param aSession 會(huì)話實(shí)例
* @param aStatus 當(dāng)前狀態(tài)
*/
- (void)callNetworkDidChange:(EMCallSession *)aSession
status:(EMCallNetworkStatus)aStatus
十一、離線發(fā)推送
1.配置屬性
EMCallOptions *options = [[EMClient sharedClient].callManager getCallOptions];
//當(dāng)對(duì)方不在線時(shí)猜憎,是否給對(duì)方發(fā)送離線消息和推送娩怎,并等待對(duì)方回應(yīng)
options.isSendPushIfOffline = NO;
[[EMClient sharedClient].callManager setCallOptions:options];
2.監(jiān)聽回調(diào)
[[EMClient sharedClient].callManager setBuilderDelegate:self];
3. 處理回調(diào)
- (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];
}
后記
未完,待續(xù)~~~