You need to enable JavaScript to run this app.
导航
iOS (Objective-C)
最近更新时间:2025.11.10 17:12:09首次发布时间:2022.04.28 16:43:35
复制全文
我的收藏
有用
有用
无用
无用

集成 RTC SDK 后,你可以使用其中接口快速构建基础应用,实现基本实时音视频通话;你也能通过阅读代码,了解音视频通话的最佳实践。
如果你想了解完整的项目实现,参看示例项目

前提条件

  • Xcode 12.5 或以上版本(本文涉及编译器的指引及示例图均参考 Xcode 13.1 )
  • 支持 iOS 11.0 或以上版本的设备
  • 使用 Objective-C 作为开发语言
  • 请确保您的项目已设置有效的开发者签名
  • 获取 Appid
  • 已获取 RTC SDK 文件

注意:
面向 iOS 平台的 SDK 仅以 .xcframework 形式提供。如果需要使用 .framework 的 SDK,你可以使用以下脚本,将 .xcframework 转为 .framework

xcframework_change_to_all_arch.sh
578.00Bytes

如果使用了 .framework,且需要将 App 上架 App Store,你必须在提交的工程中去除模拟器。可以使用以下脚本:

xcframework_remove_simulator_arch.sh
593.00Bytes

集成 SDK

步骤 1:(可选)创建项目

本步骤为如何创建一个新项目,如集成到已有项目,请直接查看步骤 2。

  1. 打开 Xcode,点击 File > New > Project

  2. 选择 iOS > App,点击 Next

    image.png

  3. 输入项目名称、团队名称、选择开发语言(这里为  Objective-C ) ,点击  Next

    image.png

  4. 选择项目存储位置,点击 Create

  5. 签名设置:进入 TARGETS > Project Name > Signing & Capabilities  ,查看  Automatically manage signing  是否勾选,若没有勾选请勾选 , 并在弹出菜单中选择  Enable Automatic

    image.png

步骤2: 解压 SDK,并拷贝到项目目录下

将下载的 VolcEngineRTC.xcframeworkRealXBase.xcframework 拖入到工程中。注意选择 Copy files to destination

步骤3:配置项目属性

  1. 配置音视频权限

    1. 找到项目中的 info.plist 文件

    2. 点击 “+” 添加音频和视频设备权限:

      1. Privacy - Microphone Usage Description ,并填入使用麦克风的原因(Value)
      2. Privacy - Camera Usage Description ,并填入使用摄像头的原因(Value)

    image.png

  2. 关闭 Bitcode (如有)

    1. 进入 TARGETS > 项目名称 > Build Setting
    2. 选择 All,搜索 bitcode
    3. Enable Bitcode 选择 NO

    image.png

  3. SDK 配置

    1. 进入 TARGETS > 项目名称 > General
    2. 选择 Frameworks, Libraries, and Embedded Content
    3. VolcEngineRTC.xcframeworkRealXBase.xcframework 和 RTCFFmpeg 设置为 Embed & Sign

    image.png

步骤4:添加隐私清单文件

应苹果公司的要求,你的 iOS App 如需要上线 App Store,必须准确描述 App 本身和集成的第三方 SDK 使用指定范围内系统接口的原因。自 2024 年 5 月 1 日起,如果你未提供相关描述,你的 App 将无法通过 App Store Connect 的审核。详见 Describing use of required reason API

如果你在 App 中集成了 3.58 及之前版本的 RTC SDK,你必须添加相关说明:

  • 如果你的 App 中没有隐私清单文件,你可以直接将 RTC SDK 的隐私清单文件添加项目根目录下。如图:
    alt
  • 如果你的 App 中已有隐私清单文件,请将 RTC SDK 的隐私清单文件中的内容添加到 App 的隐私清单文件中。

获取 RTC SDK 的隐私清单文件:

PrivacyInfo.xcprivacy.zip
933.00Bytes

实现音视频通话

基础音视频通话 API 时序图

实现流程

1. (可选)创建用户界面

根据场景需要,为你的项目创建音视频通话的用户界面。若已有用户界面,请直接进入下一步。

如果你想实现基本的音视频通话,我们建议你在项目中添加如下元素:

  • 房间ID
  • 用户 ID
  • 本地视频窗口
  • 远端视频窗口
  • 打开麦克风按钮
  • 打开摄像头按钮
  • 结束通话按钮

image.png
可参考以下代码构建用户界面:

- (void)buildUI{
    self.view.backgroundColor = [UIColor whiteColor];
  
    UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
    if (@available(iOS 11.0, *)) {
        edgeInsets = [UIApplication sharedApplication].keyWindow.safeAreaInsets;
    }
  
    [self.view addSubview:self.headerView];
    [self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(edgeInsets.top);
        make.left.right.equalTo(self.view);
        make.height.mas_equalTo(49);
    }];
  
     self.switchCameraBtn.frame = CGRectMake(22, 14, 26, 26);
    [self.headerView addSubview:self.switchCameraBtn];
    [self.switchCameraBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(22);
        make.size.mas_equalTo(26);
        make.centerY.equalTo(self.headerView);
    }];
  
    [self.headerView addSubview:self.roomIdLabel];
    [self.roomIdLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.headerView);
        make.left.greaterThanOrEqualTo(self.switchCameraBtn.mas_right).mas_offset(22);
    }];
    self.roomIdLabel.text = [NSString stringWithFormat:@"RoomID: %@",self.roomID];
  
    [self.headerView addSubview:self.switchAudioRouteBtn];
    [self.switchAudioRouteBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.mas_equalTo(-20);
        make.centerY.equalTo(self.headerView);
    }];
  
    [self.view addSubview: self.foooterView];
    [self.foooterView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.view);
        make.bottom.equalTo(self.view).offset(-edgeInsets.bottom);
        make.height.mas_equalTo(49);
    }];
  
    [self.foooterView addSubview:self.localAudioBtn];
    [self.localAudioBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(42);
        make.centerY.equalTo(self.foooterView);
    }];
  
    [self.foooterView addSubview:self.localVideoBtn];
    [self.localVideoBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.mas_equalTo(-42);
        make.centerY.equalTo(self.foooterView);
    }];
  
    [self.foooterView addSubview:self.hangUpBtn];
    [self.hangUpBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.foooterView);
    }];
  
    [self.view addSubview:self.containerView];
    [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.view);
        make.top.equalTo(self.headerView.mas_bottom);
        make.bottom.equalTo(self.foooterView.mas_top);
    }];
  
    [self.containerView addSubview:self.localView];
    [self.localView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.equalTo(self.containerView);
        make.width.height.equalTo(self.containerView).multipliedBy(0.5);
    }];
  
    [self.containerView addSubview:self.firstRemoteView];
    [self.firstRemoteView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.right.equalTo(self.containerView);
        make.width.height.equalTo(self.containerView).multipliedBy(0.5);
    }];
  
    [self.containerView addSubview:self.secondRemoteView];
    [self.secondRemoteView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.left.equalTo(self.containerView);
        make.width.height.equalTo(self.containerView).multipliedBy(0.5);
    }];
  
    [self.containerView addSubview:self.thirdRemoteView];
    [self.thirdRemoteView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.right.equalTo(self.containerView);
        make.width.height.equalTo(self.containerView).multipliedBy(0.5);
    }];
}

2. 引入头文件

在用到 SDK API 的文件中引入头文件。

#import <VolcEngineRTC/objc/ByteRTCEngine.h>
#import <VolcEngineRTC/objc/ByteRTCRoom.h>

3. 创建引擎 createRTCEngine

+ (ByteRTCEngine * _Nullable) createRTCEngine:(ByteRTCEngineConfig * _Nonnull) config
                                      delegate:(id<ByteRTCEngineDelegate> _Nullable)delegate;

首先你需要调用类 ByteRTCEngine 中的 createRTCEngine:delegate:parameters: 接口,创建一个引擎实例,以使用 RTC 提供的各种音视频能力。

你需要在该方法中传入以下参数:

参数名类型说明
configByteRTCEngineConfig*创建引擎参数配置,其中 appid 是每个应用的唯一标识符,由 RTC 控制台随机生成的。
不同的 AppId 生成的实例在 RTC 中进行音视频通话完全独立,无法互通。
delegateid<ByteRTCEngineDelegate>SDK 回调给应用层的 delegate,详见ByteRTCEngineDelegate

4. 设置本地视图 setLocalVideoCanvas

- (int)setLocalVideoCanvas:(ByteRTCVideoCanvas * _Nullable)canvas;

加入房间前,你需要设置本地视图以在通话中看到本地图像。

你需要在该方法中传入以下参数:

参数名类型说明
canvasByteRTCVideoCanvas*视图信息和渲染模式,参看 ByteRTCVideoCanvas

5. 开始视频采集 startVideoCapture

- (void)startVideoCapture;

创建引擎实例后,你需要开启视频采集,以在通话中使用视频功能。

6. 开始音频采集 startAudioCapture

- (void)startAudioCapture;

创建引擎实例后,你需要开启音频采集,以在通话中使用音频功能。

7. 创建房间实例 createRTCRoom

- ( ByteRTCRoom * _Nullable)createRTCRoom:(NSString * _Nonnull)roomId;

创建一个房间实例,以使用房间相关的功能。

roomId 应符合正则表达式:[a-zA-Z0-9_@\-]{1,128}

8. 设置房间回调事件 handler setRTCRoomDelegate

- (int)setRTCRoomDelegate:(id<ByteRTCRoomDelegate> _Nullable)roomDelegate;

你需要在该方法中传入以下参数:

参数名类型说明
roomDelegateid<ByteRTCRoomDelegate>参看 ByteRTCRoomDelegate

此方法的返回值可能为:

返回值意义
0成功
!0失败,参看 ByteRTCReturnStatus 在这里添加链接

9. 加入房间 joinRoom:userInfo:userVisibility:roomConfig:

- (int)joinRoom:(NSString *_Nullable)token userInfo:(ByteRTCUserInfo *_Nonnull)userInfo userVisibility:(BOOL)userVisibility roomConfig:(ByteRTCRoomConfig *_Nonnull)roomConfig;

创建房间实例后,你就可以调用 ByteRTCRoom 类中的 joinRoom:userInfo:roomConfig: 方法创建/加入房间。

你需要在该方法中传入以下参数:

参数名类型说明

token

NSString*

动态密钥,用于对进房用户进行鉴权验证。
进入房间需要携带 Token。测试时可使用控制台生成临时 Token,正式上线需要使用密钥 SDK 在你的服务端生成并下发 Token。
使用不同 AppID 的 App 是不能互通的。
请务必保证生成 Token 使用的 AppID 和创建引擎时使用的 AppID 相同,否则会导致加入房间失败。

userInfoByteRTCUserInfo*用户 ID。参看 ByteRTCUserInfo
userVisibilityBOOL表示用户是否可见。建议在进入房间时将用户可见性设置为 false,然后在用户需要发送音视频流时通过 setUserVisibility :{@link #ByteRTCRoom#setUserVisibility:} 将其设置为 true。当 RTC 房间中的用户数量达到上限时,此操作将失败。一个 RTC 房间最多可容纳 50 个可见用户,并且可以同时发布 30 路媒体流。更多信息,请参见 用户和流的容量
roomConfigByteRTCRoomConfig*房间参数配置,设置房间模式以及是否自动发布或订阅流。具体配置模式参看 ByteRTCRoomConfig

此方法的返回值可能为:

返回值意义
0成功
1参数不合法
2已经在房间内

10. 处理房间状态改变回调 onRoomStateChanged

- (void)rtcRoom:(ByteRTCRoom *_Nonnull)rtcRoom 
    onRoomStateChanged:(NSString *_Nonnull)roomId
             withUid:(nonnull NSString *)uid
           state:(NSInteger)state
           extraInfo:(NSString *_Nonnull)extraInfo;

加入房间后,你需要在此回调中处理首次加入房间/重连加入房间的事件。

回调参数说明:

参数名类型说明
rtcRoomByteRTCRoom*ByteRTCRoom 对象。
roomIdNSString*房间 ID
uidNSString*用户 ID

state

NSInteger

房间状态码。
0: 成功。
!0: 失败,具体原因参看 ByteRTCErrorCodeByteRTCWarningCode

extraInfo

NSString*

额外信息,如 {"elapsed":1187,"join_type":0}。其中,
joinType 表示加入房间的类型,0为首次进房,1为重连进房。
elapsed 表示加入房间耗时,即本地用户从调用 joinRoom:userInfo:roomConfig: 到加入房间成功所经历的时间间隔,单位为 ms。

11. 处理远端用户加入房间的回调 onUserJoined

- (void)rtcRoom:( ByteRTCRoom *_Nonnull)rtcRoom onUserJoined:(ByteRTCUserInfo *_Nonnull)userInfo;

加入房间后,你需要在此回调中处理远端用户加入房间的事件。

回调参数说明:

参数名类型说明
rtcRoomByteRTCRoom*ByteRTCRoom 对象。
userInfoByteRTCUserInfo*用户信息,参看 ByteRTCUserInfo

12. 处理远端视频首帧解码的回调 onFirstRemoteVideoFrameDecoded

- (void)rtcEngine:(ByteRTCEngine * _Nonnull)engine onFirstRemoteVideoFrameDecoded:(NSString * _Nonnull)streamId info:(ByteRTCStreamInfo* _Nonnull)info withFrameInfo:(ByteRTCVideoFrameInfo * _Nonnull)frameInfo;

加入房间后,你需要在此回调中处理第一帧远端视频流解码成功后的事件。

回调参数说明:

参数名类型说明
engineByteRTCEngine*ByteRTCVideo 对象
streamIdNSString*远端流ID
infoByteRTCStreamInfo*远端流的信息,参看ByteRTCStreamInfo 添加链接
frameInfoByteRTCVideoFrameInfo*视频帧信息,参看 ByteRTCVideoFrameInfo

13. 设置远端视图 setRemoteVideoCanvas:withCanvas:

- (int)setRemoteVideoCanvas:(NSString* _Nonnull)streamId
             withCanvas:(ByteRTCVideoCanvas * _Nullable)canvas;

在确认收到远端用户的第一帧视频解码回调后,你需要设置远端视图以在通话中查看远端图像。

你需要在该方法中传入以下参数:

参数名类型说明
streamIdNSString*远端流ID
canvasByteRTCVideoCanvas*视图信息和渲染模式,参看 ByteRTCVideoCanvas

14. 处理远端用户离开房间的回调 onUserLeave

- (void)rtcRoom:( ByteRTCRoom*_Nonnull)rtcRoom onUserLeave:(NSString*_Nonnull)uid reason:(ByteRTCUserOfflineReason)reason;

加入房间后,你需要在此回调中处理远端用户离开房间的事件。

回调参数说明:

参数名类型说明
uidNSString*离开房间的远端用户 ID 。
reasonByteRTCUserOfflineReason用户离开房间的原因,参看 ByteRTCUserOfflineReason

15. 离开房间 leaveRoom

- (int)leaveRoom;

在结束通话等场景下,你需要调用 leaveRoom 离开房间,结束通话过程,释放所有通话相关的资源。

此方法的返回值可能为:

返回值意义
0成功
如果用户是主持人(host)的话,房间中的其他用户将收到 rtcRoom:onUserLeave:reason: 回调。流将会停止发布。房间中的其他用户将收到 rtcRoom:onVideoPublishStateChanged:Uid:state:reason:rtcRoom:onAudioPublishStateChanged:Uid:state:reason:rtcRoom:onScreenVideoPublishStateChanged:Uid:state:reason: 和/或 rtcRoom:onScreenAudioPublishStateChanged:Uid:state:reason: 回调通知。
在用户离开房间后,其他用户将收到 rtcRoom:onUserLeave:reason: 回调通知。
<0失败,参看 ByteRTCReturnStatus

在用户离开房间后,本地客户端将收到 rtcRoom:onRoomStateChanged:withUid:state:reason: 的回调。

您需要调用 setUserVisibility: 来让自己变得可见。

16. 销毁引擎实例 destroyRTCEngine

+ (void)destroyRTCEngine;

在 RTC 引擎实例相关的业务场景全部结束后,你可调用 destroyRTCEngine 销毁由 createRTCEngine:delegate: 所创建引擎实例,并释放所有相关资源。

至此,我们实现了基本的音视频通话。

后续步骤

在实现音视频通话后,如遇无声音、无画面、视频卡顿等问题时,您可以使用诊断工具快速排查和定位异常房间及用户,并获取异常根因分析、处理建议、分析报告等。