视频互动直播是以后比拟热门的玩法,咱们常常见到有PK 连麦、直播答题、一起 KTV、电商直播、互动大班课、视频相亲等。本文将演示如何通过声网视频 SDK 在 iOS 端实现一个视频直播利用。话不多说,咱们开始入手实操。

前提筹备

在声网开发者控制台 Console https://console.agora.io 注册声网开发者账号后,须要获取我的项目 AppID。另外,开发者每个月可取得 10000 分钟的收费应用额度,可实现各类实时音视频场景。

一、 通过开源Demo,体验视频直播

可能有些人,还不理解咱们要实现的性能最初是怎么的。所以声网在 GitHub上提供一个开源的根底视频直播 Demo 我的项目,在开始开发之前你能够通过该示例我的项目体验视频直播的体验成果。

Demo 源码地址
  • Github Swift 版本:https://github.com/AgoraIO/Basic-Video-Broadcasting/tree/master/OpenLive-iOS
  • Github Objective-C 版本:https://github.com/AgoraIO/Basic-Video-Broadcasting/tree/master/OpenLive-iOS-Objective-C
成果截图

二、 视频直播的技术原理

咱们在这里要实现的是视频直播,声网的视频直播能够实现互动成果,所以也常常叫互动直播。你能够了解为是多个用户通过退出同一个频道,实现的音视频的互通,而这个频道的数据,会通过声网的 SD-RTN 实时网络来进行低延时传输的。

须要特地阐明的是,声网互动直播不同于视频直播。视频通话不辨别主播和观众,所有用户都能够发言并看见彼此;而互动直播的用户分为主播和观众,只有主播能够自在发言,且被其余用户看见。

下图展现在 App 中集成声网互动直播的根本工作流程

如上图所示,实现视频直播的步骤如下:
  1. 获取 Token:当 app 客户端退出频道时,你须要应用 Token 验证用户身份。在测试或生产环境中,从 app 服务器中获取 Token。
  2. 退出频道:调用 joinChannel 创立并退出频道。应用同一频道名称的 app 客户端默认退出同一频道。频道可了解为专用于传输实时音视频数据的通道。
  3. 在频道内公布和订阅音视频流:退出频道后,app 客户端均能够在频道内公布和订阅音视频。
App 客户端退出频道须要以下信息:
  1. App ID:声网后盾随机生成的字符串,用于辨认你的 App,可从声网控制台获取.
  2. 用户 ID:用户的惟一标识。你须要自行设置用户 ID,并确保它在频道内是惟一的。
  3. Token:在测试或生产环境中,app 客户端从你的服务器中获取 Token。在本文介绍的流程中,你能够从可从声网控制台获取获取长期 Token。长期 Token 的有效期为 24 小时。
  4. 频道名称:用于标识视频直播频道的字符串。

三、 开发环境

声网 SDK 的兼容性良好,对硬件设施和软件系统的要求不高,开发环境和测试环境满足以下条件即可:
• Xcode 9.0或以上版本
• 反对语音和视频性能的真机
• App 要求反对iOS 8.0或以上版本的iOS设施

以下是本文的开发环境和测试环境:
开发环境

• macOS 11.6版本
• Xcode Version 13.1

测试环境

• iPhone7 (iOS 15.3)

如果你此前还未接触过声网 SDK,那么你还须要做以下筹备工作
• 注册一个声网账号,进入后盾创立 AppID、获取 Token,
• 下载声网官网最新的视频直播 SDK;

四、 我的项目设置

1. 实现视频直播之前,参考如下步骤设置你的我的项目

a) 如需创立新我的项目, Xcode里,关上 Xcode 并点击 Create a new Xcode project。(创立 iOS我的项目链接:https://developer.apple.com/documentation/xcode/creating-an-xcode-project-for-an-app)

b) 抉择平台类型为 iOS、我的项目类型为 Single View App,并点击 Next。

c) 输出项目名称(Product Name)、开发团队信息(Team)、组织名称(Organization Name)和语言(Language)等我的项目信息,并点击 Next。

留神:如果你没有增加过开发团队信息,会看到 Add account… 按钮。点击该按钮并依照屏幕提示登入 Apple ID,实现后即可抉择你的 Apple 账户作为开发团队。

d) 抉择我的项目存储门路,并点击 Create。

2. 集成SDK

两种办法集成声网 SDK,抉择如下任意一种形式获取声网 iOS SDK。

办法一:应用 CocoaPods 获取 SDK

a) 开始前确保你已装置 Cocoapods。参考 Getting Started with CocoaPods 装置阐明。(Getting Started with CocoaPods 装置阐明链接:CocoaPods Guides - Getting Started

b) 在终端里进入我的项目根目录,并运行 pod init 命令。我的项目文件夹下会生成一个 Podfile 文本文件。

c) 关上 Podfile 文件,批改文件为如下内容。留神将 Your App 替换为你的 Target 名称。

platform :ios, '9.0'target 'Your App' do    pod 'AgoraRtcEngine_iOS'end
办法二:从官网获取 SDK

a) 返回 SDK 下载页面,获取最新版的声网 iOS SDK,而后解压。

b) 依据你的需要,将 libs 文件夹中的动静库复制到我的项目的 ./project_name 文件夹下(project_name 为你的项目名称)。

c) 关上 Xcode,进入 TARGETS > Project Name > Build Phases > Link Binary with Libraries 菜单,点击 + 增加如下库(如:)。在增加 AgoraRtcEngineKit.framework 文件时,还需在点击 + 后点击 Add Other…,找到本地文件并关上。

共须要增加11个库文件:

i. AgoraRtcEngineKit.frameworkii. Accelerate.frameworkiii. AudioToolbox.frameworkiv. AVFoundation.frameworkv. CoreMedia.frameworkvi. CoreML.frameworkvii. CoreTelephony.frameworkviii. libc++.tbdix. libresolv.tbdx. SystemConfiguration.frameworkxi. VideoToolbox.framework

留神1:如需反对 iOS 9.0 或更低版本的设施,请在 Xcode 中将对 CoreML.framework 的依赖设为 Optional。

d) 关上 Xcode,进入 TARGETS > Project Name > General > Frameworks, Libraries, and Embedded Content 菜单。

e) 点击 + > Add Other… > Add Files 增加对应动静库,并确保增加的动静库 Embed 属性设置为 Embed & Sign。增加实现后,我的项目会主动链接所需零碎库。

留神2: 依据 Apple 官网要求,app 的 Extension 中不容许蕴含动静库。如果我的项目中的 Extension 须要集成 SDK,则增加动静库时需将文件状态改为 Do Not Embed。
· 声网 SDK 默认应用 libc++ (LLVM),如需应用 libstdc++ (GNU),请分割 [email protected]。SDK 提供的库是 FAT Image,蕴含 32/64 位模拟器、32/64 位真机版本。

3. 权限设置

1) Xcode进入 TARGETS > Project Name > General > Signing 菜单,抉择 Automatically manage signing,并在弹出菜单中点击 Enable Automatic。

2)增加媒体设施权限
依据场景须要,在 info.plist 文件中,点击 + 图标开始增加如下内容,获取相应的设施权限:

4. 导入声网相干的类

在我的项目中导入 AgoraRtcEngineKit 类:

Objective-C 版本

// Objective-C// 导入 AgoraRtcKit 类// 自 3.0.0 版本起,AgoraRtcEngineKit 类名更换为 AgoraRtcKit// 如果获取的是 3.0.0 以下版本的 SDK,请改用 #import <AgoraRtcEngineKit/AgoraRtcEngineKit.h>#import <AgoraRtcKit/AgoraRtcEngineKit.h>// 申明 AgoraRtcEngineDelegate,用于监听回调@interface ViewController : UIViewController <AgoraRtcEngineDelegate>// 定义 agoraKit 变量@property (strong, nonatomic) AgoraRtcEngineKit *agoraKit;

Swift 版本

// Swift// 导入 AgoraRtcKit 类// 自 3.0.0 版本起,AgoraRtcEngineKit 类名更换为 AgoraRtcKit// 如果获取的是 3.0.0 以下版本的 SDK,请改用 import AgoraRtcEngineKitimport AgoraRtcKitclass ViewController: UIViewController {    ...    // 定义 agoraKit 变量    var agoraKit: AgoraRtcEngineKit?}
5. 设置声网账号信息

在 KeyCenter.swift 文件中,将你的AppID填写到对应地位,可替换“Your App ID”;
Objective-C 版本

//  Objective-C//  AppID.m//  声网 iOS Tutorial NSString *const appID = <#Your App ID#>;

Swift 版本

//  Swift// AppID.swift//  声网 iOS TutorialStatic let AppID: String = Your App ID

五、 客户端实现

本节介绍如何应用声网视频 SDK 在你的 App 里实现视频直播的几个小贴士。

1. 创立用户界面

依据场景须要,为你的我的项目创立视频直播的用户界面。咱们举荐你在我的项目中增加元素:本地视频窗口、远端视频窗口。

你能够参考以下代码创立一个根底的用户界面。

Objective-C 版本

// Objective-C// 导入 UIKit#import <UIKit/UIKit.h>@interface ViewController ()// 定义 localView 变量@property (nonatomic, strong) UIView *localView;// 定义 remoteView 变量@property (nonatomic, strong) UIView *remoteView;@end@implementation ViewController...- (void)viewDidLoad {    [super viewDidLoad];    // 调用初始化视频窗口函数    [self initViews];    // 后续步骤调用声网 API 应用的函数    [self initializeAgoraEngine];    [self setChannelProfile];    [self setClientRole];    [self setupLocalVideo];    [self joinChannel];}// 设置视频窗口布局- (void)viewDidLayoutSubviews {    [super viewDidLayoutSubviews];    self.remoteView.frame = self.view.bounds;    self.localView.frame = CGRectMake(self.view.bounds.size.width - 90, 0, 90, 160);}- (void)initViews {    // 初始化远端视频窗口。只有当远端用户为主播时,才会显示视频画面    self.remoteView = [[UIView alloc] init];    [self.view addSubview:self.remoteView];    // 初始化本地视频窗口。只有当本地用户为主播时,才会显示视频画面    self.localView = [[UIView alloc] init];    [self.view addSubview:self.localView];}

Swift 版本

// Swift// 导入 UIKitimport UIKitclass ViewController: UIViewController {    ...    // 定义 localView 变量    var localView: UIView!    // 定义 remoteView 变量    var remoteView: UIView!     override func viewDidLoad() {        super.viewDidLoad()        // 调用初始化视频窗口函数        initView()       // 后续步骤调用声网 API 应用的函数        initializeAgoraEngine()        setChannelProfile()        setClientRole()        setupLocalVideo()        joinChannel()      }    // 设置视频窗口布局    override func viewDidLayoutSubviews() {        super.viewDidLayoutSubviews()        remoteView.frame = self.view.bounds        localView.frame = CGRect(x: self.view.bounds.width - 90, y: 0, width: 90, height: 160)    }    func initView() {        // 初始化远端视频窗口。只有当远端用户为主播时,才会显示视频画面        remoteView = UIView()        self.view.addSubview(remoteView)        // 初始化本地视频窗口。只有当本地用户为主播时,才会显示视频画面        localView = UIView()        self.view.addSubview(localView)    }}
2. 实现视频直播逻辑

当初,咱们曾经将声网 iOS SDK 集成到我的项目中了。接下来咱们要在 ViewController 中调用声网 iOS SDK 提供的外围 API 实现根底的视频直播性能。

API 调用时序见下图


参考上图,依照以下步骤实现该逻辑

a) 初始化AgoraRtcEngineKit对象

在调用其余声网 API 前,须要创立并初始化 AgoraRtcEngineKit 对象。调用 sharedEngineWithAppId 办法,传入获取到的 App ID,即可初始化 AgoraRtcEngineKit 。

Objective-C 版本

// Objective-C// 输出 App ID 并初始化 AgoraRtcEngineKit 类。- (void) viewDidLoad{self.rtcEngine = [AgoraRtcEngineKit sharedEngineWithAppId:[KeyCenter AppId] delegate:self];}

Swift 版本

// Swift// 输出 App ID 并初始化 AgoraRtcEngineKit 类。private lazy var agoraKit: AgoraRtcEngineKit = {        let engine = AgoraRtcEngineKit.sharedEngine(withAppId: KeyCenter.AppId, delegate: nil)        return engine    }()

你还能够依据场景须要,在初始化时注册想要监听的回调事件,如本地用户退出频道,及解码远端用户视频首帧等。

b) 设置频道场景

调用 setChannelProfile 办法,将频道场景设为直播。一个 AgoraRtcEngineKit 只能应用一种频道场景。如果想切换为其余频道场景,须要先调用 destroy 办法销毁以后的 AgoraRtcEngineKit 对象,而后应用 sharedEngineWithAppId 办法创立一个新的对象,再调用setChannelProfile 设置新的频道场景。

Objective-C 版本

// Objective-C// 设置频道场景为直播模式[self.rtcEngine setChannelProfile:AgoraChannelProfileLiveBroadcasting];

Swift 版本

// Swift// 设置频道场景为直播模式agoraKit.setChannelProfile(.liveBroadcasting)
c) 设置用户角色

直播频道有两种用户角色:主播和观众,其中默认的角色为观众。设置频道场景为直播后,你能够在 app 中参考如下步骤设置用户角色:

让用户抉择本人的角色是主播还是观众;
调用 setClientRole 办法,而后应用用户抉择的角色进行传参。
留神,直播频道内的用户,只能看到主播的画面、听到主播的声音。退出频道后,如果你想切换用户角色,也能够调用 setClientRole 办法。

Objective-C 版本

// Objective-C// 设置用户角色- (IBAction)doBroadcastPressed:(UIButton *)sender {if (self.isBroadcaster) {        // 设置用户角色为主播        self.clientRole = AgoraClientRoleAudience;        if (self.fullSession.uid == 0) {            self.fullSession = nil;        }} else {        // 设置用户角色为观众        self.clientRole = AgoraClientRoleBroadcaster;    }        [self.rtcEngine setClientRole:self.clientRole];    [self updateInterfaceWithAnimation:YES];}

Swift 版本

// Swift// 抉择用户角色@IBAction func doBroadcasterTap(_ sender: UITapGestureRecognizer) {// 抉择用户角色为主播        selectedRoleToLive(role: .broadcaster)    }    @IBAction func doAudienceTap(_ sender: UITapGestureRecognizer) // 抉择用户角色为观众selectedRoleToLive(role: .audience)// 设置用户角色agoraKit.setClientRole(settings.role)// 设置为主播角色时if settings.role == .broadcaster {            addLocalSession()            agoraKit.startPreview()        }//设置为观众角色时let isHidden = settings.role == .audience
d) 设置本地视图

胜利初始化 AgoraRtcEngineKit 对象后,须要在退出频道前设置本地视图,以便在通话中看到本地图像。参考以下步骤设置本地视图:
· 调用 enableVideo 办法启用视频模块。
· 调用 setupLocalVideo 办法设置本地视图。

Objective-C 版本

// Objective-C// 启用视频模块。[self.rtcEngine enableVideo];// 设置本地视图。- (void)addLocalSession {    VideoSession *localSession = [VideoSession localSession];[self.videoSessions addObject:localSession];// 设置本地视图。    [self.rtcEngine setupLocalVideo:localSession.canvas];    [self updateInterfaceWithAnimation:YES];}// VideoSession局部//  VideoSession.m#import "VideoSession.h"@implementation VideoSession- (instancetype)initWithUid:(NSUInteger)uid {    if (self = [super init]) {        self.uid = uid;                self.hostingView = [[UIView alloc] init];        self.hostingView.translatesAutoresizingMaskIntoConstraints = NO;                self.canvas = [[AgoraRtcVideoCanvas alloc] init];        self.canvas.uid = uid;        self.canvas.view = self.hostingView;        self.canvas.renderMode = AgoraVideoRenderModeHidden;    }    return self;}+ (instancetype)localSession {    return [[VideoSession alloc] initWithUid:0];}@end

Swift 版本

// Swift// 启用视频模块。agoraKit.enableVideo()// 设置本地视图。agoraKit.setupLocalVideo(videoCanvas)// VideoSession局部// VideoSession.swifthostingView = VideoView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))hostingView.translatesAutoresizingMaskIntoConstraints = falsecanvas = AgoraRtcVideoCanvas()canvas.uid = uidcanvas.view = hostingView.videoViewcanvas.renderMode = .hidden
e) 退出频道

频道是人们在同一个视频直播中的公共空间。实现初始化和设置本地视图后(视频直播场景),你就能够调用 joinChannelByToken 办法退出频道。你须要在该办法中传入如下参数:

  1. channelId: 传入能标识频道的频道 ID。输出频道 ID 雷同的用户会进入同一个频道。
  2. token: 传入能标识用户角色和权限的 Token。你能够设置如下值:
  3. nil 。
  4. 控制台中生成的长期 Token。一个长期 Token 的有效期为 24 小时,详情见获取长期 Token。
  5. 你的服务器端生成的正式 Token。实用于对平安要求较高的生产环境,详情见生成 Token。若我的项目已启用 App 证书,请应用 Token。
  6. uid: 本地用户的 ID。数据类型为整型,且频道内每个用户的 uid 必须是惟一的。若将 uid 设为 0,则 SDK 会主动调配一个 uid ,并在 joinSuccessBlock 回调中报告。
  7. joinSuccessBlock:胜利退出频道回调。 joinSuccessBlock 优先级高于 didJoinChannel ,2 个同时存在时, didJoinChannel 会被疏忽。须要有 didJoinChannel 回调时,请将 joinSuccessBlock 设置为 nil 。

更多的参数设置注意事项请参考 joinChannelByToken 接口中的参数形容。
Objective-C 版本

// Objective-C// 退出频道。self.rtcEngine joinChannelByToken:[KeyCenter Token] channelId:self.roomName info:nil uid:0 joinSuccess:nil 

Swift 版本

// Swift// 退出频道。agoraKit.joinChannel(byToken: KeyCenter.Token, channelId: channelId, info: nil, uid: 0, joinSuccess: nil)
f) 设置远端视图

视频互动直播中,通常你也须要看到其余主播。远端主播胜利退出频道后,SDK 会触发 didJoinedOfUid 回调,该回调中会蕴含这个远端主播的 uid 信息。在该回调中调用 setupRemoteVideo 办法,传入获取到的 uid,设置远端主播的视图。

Objective-C 版本

// Objective-C// 监听 didJoinedOfUid 回调// 远端主播退出频道时,会触发该回调- (void)rtcEngine:(AgoraRtcEngineKit *)engine didJoinedOfUid:(NSUInteger)uid elapsed:(NSInteger)elapsed {    AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];    videoCanvas.uid = uid;    videoCanvas.renderMode = AgoraVideoRenderModeHidden;    videoCanvas.view = self.remoteView;    // 设置远端视图    [self.agoraKit setupRemoteVideo:videoCanvas];}

Swift 版本

// Swift//须要在额定增加以下代码extension LiveRoomViewController: AgoraRtcEngineDelegate {    // 监听 didJoinedOfUid 回调    // 远端主播退出频道时,会触发该回调    func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {        guard videoSessions.count <= maxVideoSession else {            return        }        let userSession = videoSession(of: uid)        // 设置远端视图        agoraKit.setupRemoteVideo(userSession.canvas)    }  }
g) 来到频道

依据场景须要,如完结通话、敞开 App 或 App 切换至后盾时,调用 leaveChannel 来到以后通话频道。

Objective-C 版本

// Objective-C// 来到频道的步骤- (void)leaveChannel {    [self setIdleTimerActive:YES];[self.rtcEngine setupLocalVideo:nil]; // nil means unbind// 来到频道。    [self.rtcEngine leaveChannel:nil];    // leave the channel, callback = nil    if (self.isBroadcaster) {        [self.rtcEngine stopPreview];    }        for (VideoSession *session in self.videoSessions) {        [session.hostingView removeFromSuperview];    }    [self.videoSessions removeAllObjects];        if ([self.delegate respondsToSelector:@selector(liveVCNeedClose:)]) {        [self.delegate liveVCNeedClose:self];    }}

Swift 版本

// Swift// 来到频道的步骤func leaveChannel() {        // Step 1, release local AgoraRtcVideoCanvas instance        agoraKit.setupLocalVideo(nil)        // Step 2, leave channel and end group chat        agoraKit.leaveChannel(nil)                // Step 3, if current role is broadcaster,  stop preview after leave channel        if settings.role == .broadcaster {            agoraKit.stopPreview()        }        setIdleTimerActive(true)        navigationController?.popViewController(animated: true)    }
h) 销毁AgoraRtcEngineKit对象

最初,来到频道,咱们须要调用 destroy 销毁 AgoraRtcEngineKit 对象,开释声网 SDK 应用的所有资源。
Objective-C 版本

// Objective-C// 将以下代码填入你定义的函数中[AgoraRtcEngineKit destroy];

Swift 版本

// Swift// 将以下代码填入你定义的函数中AgoraRtcEngineKit.destroy()


至此,实现声网视频 SDK 的集成,运行看看成果。拿两部手机装置编译好的App,退出同一个频道名,别离抉择主播角色和观众角色,如果2个手机都能看见同一个本人,阐明你胜利了。

如果你在集成开发过程中遇到问题,能够拜访 RTE 开发者社区 吐槽与声网工程师交换。