跳到主要内容

一对一通话

本页介绍了一对一呼叫的主要功能,包括如何从您的应用程序拨打、接听、处理和结束呼叫。


关键类介绍

  • RCCallPlusClientRCCallPlusClient 单例对象是 CallPlus for iOS SDK 的核心类,用于管理客户端呼叫行为,例如发起、接听、挂断通话,操作音视频设备,管理通话记录等。例如,RCCallPlusClient 有以下关键属性:

    属性名称类型说明
    currentSessionRCCallPlusSession代表当前正在进行中的通话。
    enableMicrophoneBOOL设置或获取本地用户是否已启用麦克风。默认通话时开启麦克风, 用户通话中设置开关麦克风,对端用户会在 didRemoteMicrophoneStateChanged:disabled:userId: 收到变更音频状态的通知。
    enableSpeakerBOOL设置或获取本地用户是否已启用扬声器。默认音频通话时使用听筒,视频通话时使用扬声器。
  • RCCallPlusSessionRCCallPlusSession 对象代表一则通话的所有信息,具有以下属性。

    名称类型说明
    callIdNSString唯一通话标识。
    callerUserIdNSString发起者 userId。
    inviterUserIdNSString邀请者 userId,呼入有值;呼出时,只为本地用户 userId。
    callTypeRCCallPlusType通话类型:单呼、群呼。
    mediaTypeRCCallPlusMediaType媒体类型:音频、音视频。
    callUsersNSArray<RCCallPlusUser *>通话成员列表(不含本端)。RCCallPlusUser 对象包含用户 Id 以及用户状态。
    callStateRCCallPlusCallState通话状态。
  • RCCallPlusCallRecordRCCallPlusCallRecord 对象代表一则通话记录,其中包含了与 RCCallPlusSession 类似的通话信息,还提供了通话开始与结束的时间戳、通话时长、通话结束原因等信息。

  • RCCallPlusEventDelegate:委托协议 RCCallPlusEventDelegate 提供了来电事件(didReceivedCall:extra:)、通话建立成功(didCallConnected:)、收到通话记录(didReceivedCallRecord:)等事件相关回调。

  • RCCallPlusResultDelegate: 委托协议RCCallPlusResultDelegate 提供了调用 CallPlus API 后的异步执行结果回调。


添加事件代理

CallPlus for iOS SDK 提供以下两个与呼叫事件相关的委托协议:

请在应用程序初始化或呼叫模块初始化时设置以下事件代理:

/// 设置事件代理
[[RCCallPlusClient sharedInstance] setCallEventDelegate:self];
/// 响应api代理
[[RCCallPlusClient sharedInstance] setCallResultDelegate:self];

注意

如果未设置 RCCallPlusEventDelegate 代理,则用户无法接收 didReceivedCall 回调事件。请在 connectWithToken 方法前添加 RCCallPlusEventDelegate 代理,否则用户在未连接的情况下,通过离线推送打开应用连接 IM 后无法收到通话。


连接融云服务器

要使用 CallPlus SDK 的通话能力,必须先通过 RongCoreClientconnect 方法连接融云服务器,传入用户身份令牌(Token),向融云服务器验证用户身份。

获取 Token 以后,可以调用 connectWithToken 方法连接到融云服务器。

// 连接 IM 服务
[[RCCoreClient sharedCoreClient] connectWithToken:@"从您服务器端获取的 Token"
dbOpened:^(RCDBErrorCode code) {}
success:^(NSString *userId) {}
error:^(RCConnectErrorCode status) {}];


处理本地与远端视频视图

在主叫方发起通话前,被叫方接听通话时需要使用 setVideoView: 方法设置视频视图:

在视频通话期间,呼叫者和被呼叫者可以在需要时使用 setVideoView:removeVideoViewByUserId: 方法设置或移除他们的流视频的图像。需要注意的是,用户需要打开摄像头才可以在设置视图后看到采集的画面,移除视图时也需要主动关闭摄像头。

本地视频视图

您可以在发起通话前、接听通话前设置本地视频视图,用于本地预览摄像头采集的视频。

/// 打开摄像头
[[RCCallPlusClient sharedInstance] startCamera];
/// 创建本地视图
RCCallPlusVideoView *localView = [RCCallPlusVideoView new];
/// 设置本地视图需要显示的本地用户 id
localView.userId = @"localUserId";
/// 指定本地视图尺寸
localView.frame = CGRectMake(100, 100, 100, 100);
[self.view addSubview:localView];
[[RCCallPlusClient sharedInstance] setVideoView:localView];
名称说明
RCCallPlusVideoView显示本地视频视图。userId 必填,用于指定需要显示视频视图的本地用户 id;renderMode 用于设置渲染模式,默认使用 RCCallPlusRenderModeAspectFit 完整显示,填充黑边,等比例填充,直到一个维度到达区域边界。

远程视频视图

在通话接通前,主叫和被叫方可以设置远端视频视图,用于显示对方画面。

/// 创建远端视图
RCCallPlusRemoteVideoView *remoteView = [RCCallPlusRemoteVideoView new];
/// 设置本地视图需要显示的本地用户 id
remoteView.userId = @"remoteUserId";
/// 指定本地视图显示大流
remoteView.isTiny = NO;
/// 指定本地视图尺寸
remoteView.frame = CGRectMake(200, 100, 100, 100);
[self.view addSubview:remoteView];
[[RCCallPlusClient sharedInstance] setVideoView:remoteView];
名称说明
RCCallPlusRemoteVideoView显示对端视频视图。属性:userId 必填,用于指定需要显示视频视图的远端用户 id;renderMode 用于设置渲染模式,默认使用 RCCallPlusRenderModeAspectFit 完整显示, 填充黑边, 等比例填充, 直到一个维度到达区域边界; isTiny 用于设置是否显示小流,默认值 NO 显示是大流。

发起呼叫

注意

从 CallPlus 2.X 开始,新增 startCallWithUserIds:callType:mediaType:pushConfig:extra: 方法,支持在发起呼叫时通过配置推送属性自定义远程推送标题等属性。支持携带自定义数据。如不需要配置推送属性,可以使用 startCallWithUserIds:callType:mediaType:

要发起呼叫,主叫方的客户端应用程序中必须先注册 RCCallPlusResultDelegate 事件委托。该委托使主叫用户的应用程序能够通过其委托方法接收调用通话方法的异步回调结果。

通过在 startCallWithUserIds:callType:mediaType:pushConfig:extra: 方法中提供被叫用户的用户 ID、通话类型、通话媒体类型来发起呼叫。

注意

发起呼叫时需要保证当前没有正在进行的通话。

/// 开始呼叫,并携带推送配置
RCCallPlusPushConfig *pushConfig = [[RCCallPlusPushConfig alloc] init];
pushConfig.disablePushTitle = NO;
[[RCCallPlusClient sharedInstance] startCallWithUserIds:@[@"remoteUserId"]
callType:RCCallPlusSingleType
mediaType:RCCallPlusAudioVideoMediaType
pushConfig:pushConfig
extra:@"extraString"];

/// 开始通话回调
/// @param code 状态码, 0:成功 非0:失败
/// @param callId 通话id
/// @param busylineUsers 忙线用户列表
- (void)didStartCallResultCode:(RCCallPlusCode)code
callId:(nullable NSString *)callId
busylineUsers:(nullable NSArray<RCCallPlusUser *> *)busylineUsers {
}

接听通话

重要

非兼容性变更:从 CallPlus 2.X 开始,不再提供 CallPlus 1.X 的 didReceivedCall: 回调方法。请改为使用携带 extra 字段的 didReceivedCall:extra: 方法。

要接收来电事件,被叫方的客户端应用程序中必须先注册 RCCallPlusEventDelegate 事件委托,实现 didReceivedCall:extra 方法。使用 [[RCCallPlusClient sharedInstance] acceptWithCallId:callId];[[RCCallPlusClient sharedInstance] hangupWithCallId:callId]; 方法接受或拒绝呼叫。如果呼叫被接受,CallPlus SDK 将自动建立媒体会话,并通过 didCallConnected: 方法告知双方用户通话已经建立。一对一通话被叫用户接听通话后,通话计时开始。

/// 接收到呼入会话通知
/// @param session 会话
- (void)didReceivedCall:(RCCallPlusSession *)session {
[[RCCallPlusClient sharedInstance] acceptWithCallId:session.callId];
}
/// 建立通话成功
/// @param session 会话
- (void)didCallConnected:(RCCallPlusSession *)session {
}

呼叫被接受时,CallPlus SDK 将自动建立一对一类型的通话,通话开始计时计费。


处理当前通话

音频

在通话过程中,主叫方和被叫方的音频都可以通过 [RCCallPlusClient sharedInstance].enableMicrophonemuteAllRemoteAudio: 方法改变麦克风状态或者静音远端音频。如果一方更改麦克风状态,另一方会通过 RCCallPlusEventDelegate 代理对象的方法 didRemoteMicrophoneStateChanged:disabled:userId: 接收事件回调。

/// 关闭麦克风
[RCCallPlusClient sharedInstance].enableMicrophone = NO;

/// 静音所有远端流
[[RCCallPlusClient sharedInstance] muteAllRemoteAudio:YES];

/// 远端用户音频静默改变通知
/// @param callId 通话id
/// @param disabled YES:关闭,NO:打开
/// @param userId 远端用户id
- (void)didRemoteMicrophoneStateChanged:(NSString *)callId
disabled:(BOOL)disabled
userId:(NSString *)userId {
}

开关摄像头

在通话过程中,主叫方和被叫方的摄像头都可以通过 startCamerastopCamera 方法启用或禁用。如果一方更改摄像头开关状态,另一方会通过 RCCallPlusEventDelegate 代理对象的方法 didRemoteCameraStateChanged:disabled:userId: 接收事件回调。

注意

CallPlus SDK 视频通话需要用户主动打开或关闭摄像头。

/// 关闭摄像头
[[RCCallPlusClient sharedInstance] stopCamera];

/// 远端用户视频静默改变通知
/// @param callId 通话id
/// @param disabled YES:关闭,NO:打开
/// @param userId 远端用户id
- (void)didRemoteCameraStateChanged:(NSString *)callId
disabled:(BOOL)disabled
userId:(NSString *)userId {
}

切换前后摄像头

用户在视频通话中切换前后摄像头切换,使用 switchCamera 方法。

[[RCCallPlusClient sharedInstance] switchCamera];

配置视频设置

在视频开始之前或通话过程中可以调整摄像头采集的配置信息,调整本端发送视频流的分辨率、码率、帧率:

RCCallPlusVideoConfig *videoConfig = [[RCCallPlusVideoConfig alloc]init];
// 配置视频分辨率 默认分辨率 640X480
videoConfig.videoResolution = RC_VIDEO_PROFILE_720P;
// 配置视频最大码率 默认 900
videoConfig.maxVideoBitrate = 1000;
// 配置视频帧率 默认 15Fps
videoConfig.frameRate = RCCallPlusVideoFps15;
[[RCCallPlusClient sharedInstance] setVideoConfig:videoConfig];

切换媒体类型

仅在一对一通话过程中,支持切换通话媒体类型。主叫方和被叫方都可以通过 requestChangeMediaType: 方法发起切换媒体类型请求。SDK 内部以异步方式执行该方法,请求的发起方可通过 RCCallPlusResultDelegate 代理对象的 didRequestChangeMediaType:code:transactionId:callId: 方法判断请求是否发起成功。

注意

CallPlus SDK 如果视频通话降级为音频通话 SDK 内部会关闭摄像头,音频通话升级为视频通话 SDK 内部会打开摄像头。

/// 请求切换媒体类型
[[RCCallPlusClient sharedInstance] requestChangeMediaType:RCCallPlusAudioVideoMediaType];

/// 类型切换请求结果回调
/// @param mediaType 媒体类型 RCCallPlusMediaType
/// @param code 状态码, 0:成功 非0:失败
/// @param transactionId 本次任务标识id
/// @param callId 通话id
- (void)didRequestChangeMediaType:(RCCallPlusMediaType)mediaType
code:(RCCallPlusCode)code
transactionId:(nullable NSString *)transactionId
callId:(NSString *)callId {
}

远端用户会通过 RCCallPlusEventDelegate 代理对象的方法 didReceivedChangeMediaTypeRequest:transactionId:userId: 收到切换媒体类型请求,通过 replyChangeMediaType:isAgreed: 方法同意或拒绝请求。

/// 收到媒体类型变更请求(仅单聊)
/// @param mediaType 媒体类型
/// @param transactionId 请求操作 id
/// @param userId 用户 id
- (void)didReceivedChangeMediaTypeRequest:(RCCallPlusMediaType)mediaType transactionId:(NSString *)transactionId userId:(NSString *)userId {
/// 同意变更媒体类型请求
[[RCCallPlusClient sharedInstance] replyChangeMediaType:transactionId isAgreed:YES];
}

replyChangeMediaType:isAgreed: 方法在 SDK 内部以异步方式,调用该方法后,结果通过 RCCallPlusResultDelegate 代理对象的 didReplyChangeMediaType:transactionId:callId:isAgreed: 方法返回是否成功地回复了该请求。

/// 响应媒体类型切换结果回调
/// @param code 状态码, 0:成功 非0:失败
/// @param transactionId 本次任务标识id
/// @param isAgreed YES:同意, NO:不同意
/// @param callId 通话id
- (void)didReplyChangeMediaType:(RCCallPlusCode)code
transactionId:(nullable NSString *)transactionId
callId:(NSString *)callId
isAgreed:(BOOL)isAgreed {
}

在请求被成功回复后(或者超时未回复),媒体类型变更最终的结果会通过 RCCallPlusEventDelegate 代理对象的方法 didReceivedChangeMediaTypeRequest:transactionId:userId: 回调给请求方与确认方。

/// 媒体类型变更结果(仅单聊)
/// @param transactionId 请求操作 id
/// @param userId 用户 id
/// @param mediaType 媒体类型
/// @param code 变更结果
- (void)didReceivedChangeMediaTypeResult:(RCCallPlusMediaType)mediaType
transactionId:(NSString *)transactionId
userId:(NSString *)userId
code:(RCCallChangeMediaTypeState)code {
}

在远端用户响应之前可以取消请求。发起请求变更媒体类型的一方,可以通过 cancelChangeMediaType: 方法向服务端申请取消媒体切换的请求。取消结果可在 RCCallPlusResultDelegate 代理对象的 didCancelChangeMediaType:transactionId:callId: 方法返回的状态码获取。

/// 取消请求切换媒体类型
[[RCCallPlusClient sharedInstance] cancelChangeMediaType:transactionId];

/// 取消类型切换结果回调
/// @param code 状态码, 0:成功 非0:失败
/// @param transactionId 本次任务标识id
/// @param callId 通话id
- (void)didCancelChangeMediaType:(RCCallPlusCode)code
transactionId:(nullable NSString *)transactionId
callId:(NSString *)callId {
}

通话中接听来电

您可以在通话过程中接听来电。因为一次只能有一个在进行中的通话,所以正在进行的通话需要先挂断,才能接听新来电。

使用 acceptWithCallId: 接受新来电,SDK 内部自动挂断正在进行的通话,新来电将变为当前通话。

[[RCCallPlusClient sharedInstance] acceptWithCallId:callId];

您也可以直接使用 hangupWithCallId: 拒绝新来电。callId 为新来电的的唯一通话标识 。

注意

CallPlus SDK 不支持在通话过程中保持和恢复通话。


通话中精准计时

CallPlus 服务端可统一下发通话开始时间,确保各端计时准确、一致,具体支持以下两种方案:

CallPlus 会在通话连接成功后将两个时间戳都回调给 SDK 端(可能会因校准行为导致多次回调),应用程序可以通过计算回调的时间戳与本地时间之间的差值得到精确的通话时长。

/// 当前通话开始时间
/// @param callStartTime 当前通话开始时间
- (void)didCallStartTimeFromServer:(NSInteger)callStartTime {

}

注意

为减小误差,CallPlus SDK 会根据用户的网络情况以及本地时间的差异,对通话开始的时间戳进行校准,因此可能存在同一个通话多次回调该方法的情况。建议您在使用时注意及时更新。


结束通话

注意

从 CallPlus 2.X 开始,新增 hangupWithCallId:pushConfig: 方法,支持在挂断时通过配置推送属性自定义远程推送标题等属性。如不需要配置推送属性,可以使用 hangup

挂断与拒绝接听动作均使用 hangup 方法。应用程序可使用 [[RCCallPlusClient sharedInstance] hangup]; 方法结束当前正在进行中的通话,或者使用 hangupWithCallId: 方法结束指定 callId 的通话。应用程序可通过 RCCallPlusResultDelegate 代理对象的 didHangupCallResultCode:callId: 方法接收 API 的执行结果。

/// 挂断指定 callId 通话,并携带推送配置
RCCallPlusPushConfig *pushConfig = [[RCCallPlusPushConfig alloc] init];
pushConfig.disablePushTitle = NO;
[[RCCallPlusClient sharedInstance] hangupWithCallId:@"callId"
pushConfig:pushConfig];

/// 挂断通话回调
/// @param code 状态码, 0:成功 非0:失败
/// @param callId 通话id
- (void)didHangupCallResultCode:(RCCallPlusCode)code callId:(NSString *)callId {
}

如果通话为一对一类型,一方挂断则双方同时挂断,融云将停止对通话计时计费。


管理通话记录

CallPlus 提供服务端通话记录管理能力,包括查询用户通话记录列表、删除通话记录等功能。一则通话记录对应一个 RCCallPlusCallRecord 对象,其中包含通话 ID、参与用户 ID、通话开始与结束的时间戳、通话时长等信息。

CallPlus SDK 不提供本地通话记录。

通话结束后获取通话记录

通话结束(或拒接来电)后可以通过 RCCallPlusEventDelegate 代理对象的方法 didReceivedCallRecord: 立即获取通话记录。

/// 己方参与过(或拒接)的通话结束时,生成通话记录收到该通知
/// @param callRecord 通话记录
- (void)didReceivedCallRecord:(RCCallPlusCallRecord *)callRecord {
}

检索服务端通话记录

应用程序可以从融云服务端获取用户的通话历史记录。

从 2.1.0 版本,RCCallPlusClient 新增 getRemoteCallRecordsWithTime:count:order: 方法,支持倒序查询通话记录。例如,分页获取最近的通话记录。首次可以将 syncTime 设置为 -1。如果需要继续查询,可以使用回调方法中返回的 syncTime 作为下一次查询的 syncTime 值。

/// 获取远端通话记录,count 最大为 100
[[RCCallPlusClient sharedInstance] getRemoteCallRecordsWithTime:-1 count:30 order:1];

如果采用正序查询(order0),可以从最早的记录或指定时间戳开始查询。

应用程序可以从 RCCallPlusResultDelegate 代理对象中获取服务端返回的通话对象列表。建议使用 2.1.0 版本新增的代理方法 didGetRemoteCallRecords:hasMore:syncTime:code:

/// 通话记录获取结果回调
/// @param records 未删除的通话记录
/// @param hasMore 是否还有未拉取的通话记录
/// @param syncTime 时间戳
/// @param code 状态码, 0:成功 非0:失败
- (void)didGetRemoteCallRecords:(nullable NSArray <RCCallPlusCallRecord *>*)records
hasMore:(BOOL)hasMore
syncTime:(NSTimeInterval)syncTime
code:(RCCallPlusCode)code {
}

删除通话记录

CallPlus SDK 不提供本地通话记录。如果使用以下方法删除通话记录,则从服务端删除属于当前用户的通话记录。批量删除通话记录只需要传入通话 ID,不区分通话类型。

/// 批量删除通话记录
/// @param callIds 通话id集合
- (void)deleteCallRecordsFromServerByCallIds:(NSArray<NSString *> *)callIds;

/// 删除所有通话记录
- (void)deleteAllCallRecordsFromServer;

管理通话质量

用户可以收到有关通话质量变化的通知,以便他们可以检查自己的网络连接。

设置 RCCallPlusStatusReportDelegate

要检测通话质量的变化,需要设置 RCCallPlusStatusReportDelegate 并实现对应的代理方法,对应的方法每 1 秒回调一次。RCCallPlusStatusReportDelegate 有以下方法:

方法说明
- (void)didReceivePacketLoss:(NSDictionary<NSString *, RCCallPlusPacketLossStats *>*)stats;接收丢包率信息回调。stats 对象中: key 表示用户 Id;RCCallPlusPacketLossStats 携带 丟包率(0-100),码率(kbps)。
- (void)didSendPacketLoss:(float)lossRate delay:(int)delay;发送丢包率信息回调。 lossRate 表示丢包率(0-100),delay 表示发送端的网络延迟(ms)。