基於 Agora SDK 實現 iOS 端的多人視訊互動
視訊互動直播是當前比較熱門的玩法,我們經常見到有PK 連麥、直播答題、一起 KTV、電商直播、互動大班課、視訊相親等。
本文將教你如何通過聲網Agora 視訊 SDK 在iOS端實現一個視訊直播應用。註冊聲網賬號後,開發者每個月可獲得 10000 分鐘的免費使用額度,可實現各類實時音視訊場景。
話不多說,我們開始動手實操。
一、 通過開源Demo,體驗視訊直播
可能有些人,還不瞭解我們要實現的功能最後是怎樣的。所以我們在 GitHub上提供一個開源的基礎視訊直播示例專案,在開始開發之前你可以通過該示例專案體驗視訊直播的體驗效果。
Agora 在 GitHub 上提供開源的互動直播示例專案 OpenLive-iOS-Objective-C 與 OpenLive-iOS-Swift。在實現相關功能前,你可以下載並檢視原始碼。
Objective-C Github連結:Basic-Video-Broadcasting/OpenLive-iOS-Objective-C at master · AgoraIO/Basic-Video-Broadcasting · GitHub 4 Swift Github連結:Basic-Video-Broadcasting/OpenLive-iOS at master · AgoraIO/Basic-Video-Broadcasting · GitHub 1
二、 視訊直播的技術原理
我們在這裡要實現的是視訊直播,Agora 的視訊直播可以實現互動效果,所以也經常叫互動直播。你可以理解為是多個使用者通過加入同一個頻道,實現的音視訊的互通,而這個頻道的資料,會通過聲網的 Agora SD-RTN 實時網路來進行低延時傳輸的。
需要特別說明的是,Agora互動直播不同於視訊直播。視訊通話不區分主播和觀眾,所有使用者都可以發言並看見彼此;而互動直播的使用者分為主播和觀眾,只有主播可以自由發言,且被其他使用者看見。
下圖展示在 App 中整合 Agora 互動直播的基本工作流程:
如圖所示,實現視訊直播的步驟如下:
- 獲取 Token:當 app 客戶端加入頻道時,你需要使用 Token 驗證使用者身份。在測試或生產環境中,從 app 伺服器中獲取 Token。
- 加入頻道:呼叫 joinChannel 建立並加入頻道。使用同一頻道名稱的 app 客戶端預設加入同一頻道。頻道可理解為專用於傳輸實時音視訊資料的通道。
- 在頻道內釋出和訂閱音視訊流:加入頻道後,app 客戶端均可以在頻道內釋出和訂閱音視訊。
App 客戶端加入頻道需要以下資訊:
- App ID:Agora 隨機生成的字串,用於識別你的 App,可從 Agora 控制檯獲取,(Agora控制檯連結:Dashboard
- 使用者 ID:使用者的唯一標識。你需要自行設定使用者 ID,並確保它在頻道內是唯一的。
- Token:在測試或生產環境中,app 客戶端從你的伺服器中獲取 Token。在本文介紹的流程中,你可以從 Agora 控制檯獲取臨時 Token。臨時 Token 的有效期為 24 小時。
- 頻道名稱:用於標識視訊直播頻道的字串。
三、 開發環境
聲網Agora SDK 的相容性良好,對硬體裝置和軟體系統的要求不高,開發環境和測試環境滿足以下條件即可: • Xcode 9.0或以上版本 • 支援語音和視訊功能的真機 • App 要求支援iOS 8.0或以上版本的iOS裝置
以下是本文的開發環境和測試環境:
開發環境 • macOS 11.6版本 • Xcode Version 13.1
測試環境 • iPhone7 (iOS 15.3)
如果你此前還未接觸過聲網 Agora SDK,那麼你還需要做以下準備工作: • 註冊一個聲網賬號,進入後臺建立 AppID、獲取 Token, • 下載聲網官方最新的視訊直播SDK;(視訊直播SDK連結:下載 - 視訊通話 - 文件中心 - 聲網Agora
四、 專案設定
1. 實現視訊直播之前,參考如下步驟設定你的專案:
a) 如需建立新專案, Xcode裡,開啟 Xcode 並點選 Create a new Xcode project。(建立 iOS專案連結:https://developer.apple.com/documentation/xcode/creating-an-xcode-project-for-an-app) 1
b) 選擇平臺型別為 iOS、專案型別為 Single View App,並點選 Next。
c) 輸入專案名稱(Product Name)、開發團隊資訊(Team)、組織名稱(Organization Name)和語言(Language)等專案資訊,並點選 Next。 注意:如果你沒有新增過開發團隊資訊,會看到 Add account… 按鈕。點選該按鈕並按照螢幕提示登入 Apple ID,完成後即可選擇你的 Apple 賬戶作為開發團隊。
d) 選擇專案儲存路徑,並點選 Create。
2. 整合SDK
選擇如下任意一種方式獲取最新版 Agora iOS SDK。
方法一:使用 CocoaPods 獲取 SDK
a) 開始前確保你已安裝 Cocoapods。參考 Getting Started with CocoaPods 安裝說明。(Getting Started with CocoaPods 安裝說明連結:CocoaPods Guides - Getting Started 1
```
platform :ios, '9.0'
target 'Your App' do pod 'AgoraRtcEngine_iOS' end ```
b) 在終端裡進入專案根目錄,並執行 pod init 命令。專案資料夾下會生成一個 Podfile 文字檔案。 c) 開啟 Podfile 檔案,修改檔案為如下內容。注意將 Your App 替換為你的 Target 名稱。 方法二:從官網獲取 SDK a) 前往 SDK 下載頁面,獲取最新版的 Agora iOS SDK,然後解壓。(視訊直播SDK連結:下載 - 視訊通話 - 文件中心 - 聲網Agora b) 根據你的需求,將 libs 資料夾中的動態庫複製到專案的 ./project_name 資料夾下(project_name 為你的專案名稱)。 c) 開啟 Xcode,進入 TARGETS > Project Name > Build Phases > Link Binary with Libraries 選單,點選 + 新增如下庫(如:)。在新增 AgoraRtcEngineKit.framework 檔案時,還需在點選 + 後點擊 Add Other…,找到本地檔案並開啟。
共需要新增11個庫檔案: i. AgoraRtcEngineKit.framework ii. Accelerate.framework iii. AudioToolbox.framework iv. AVFoundation.framework v. CoreMedia.framework vi. CoreML.framework vii. CoreTelephony.framework viii. libc++.tbd ix. libresolv.tbd x. SystemConfiguration.framework xi. VideoToolbox.framework 注意:如需支援 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。新增完成後,專案會自動連結所需系統庫。
注意: · 根據 Apple 官方要求,app 的 Extension 中不允許包含動態庫。如果專案中的 Extension 需要整合 SDK,則新增動態庫時需將檔案狀態改為 Do Not Embed。 · Agora SDK 預設使用 libc++ (LLVM),如需使用 libstdc++ (GNU),請聯絡 [email protected]。SDK 提供的庫是 FAT Image,包含 32/64 位模擬器、32/64 位真機版本。
3. 許可權設定
- Xcode進入 TARGETS > Project Name > General > Signing 選單,選擇 Automatically manage signing,並在彈出選單中點選 Enable Automatic。
- 新增媒體裝置許可權 根據場景需要,在 info.plist 檔案中,點選 + 圖示開始新增如下內容,獲取相應的裝置許可權:
4. 匯入Agora相關的類
在專案中匯入 AgoraRtcEngineKit 類:
```
// Objective-C
// 匯入 AgoraRtcKit 類
// 自 3.0.0 版本起,AgoraRtcEngineKit 類名更換為 AgoraRtcKit
// 如果獲取的是 3.0.0 以下版本的 SDK,請改用 #import
import
// 宣告 AgoraRtcEngineDelegate,用於監聽回撥
@interface ViewController : UIViewController
// Swift // 匯入 AgoraRtcKit 類 // 自 3.0.0 版本起,AgoraRtcEngineKit 類名更換為 AgoraRtcKit // 如果獲取的是 3.0.0 以下版本的 SDK,請改用 import AgoraRtcEngineKit import AgoraRtcKit class ViewController: UIViewController { ... // 定義 agoraKit 變數 var agoraKit: AgoraRtcEngineKit? } ```
5. 設定Agora賬號資訊
在KeyCenter.swift檔案中,將你的AppID填寫到對應位置,可替換“Your App ID”;
``` // Objective-C // AppID.m // Agora iOS Tutorial NSString *const appID = <#Your App ID#>;
// Swift // AppID.swift // Agora iOS Tutorial Static let AppID: String = Your App ID ```
五、 客戶端實現
本節介紹如何使用Agora視訊SDK在你的App裡實現視訊直播的幾個小貼士:
1. 建立使用者介面
根據場景需要,為你的專案建立視訊直播的使用者介面。我們推薦你在專案中新增元素:本地視訊視窗、遠端視訊視窗。
你可以參考以下程式碼建立一個基礎的使用者介面。
``` // Objective-C // 匯入 UIKit
import
@interface ViewController () // 定義 localView 變數 @property (nonatomic, strong) UIView localView; // 定義 remoteView 變數 @property (nonatomic, strong) UIView remoteView; @end @implementation ViewController ... - (void)viewDidLoad { [super viewDidLoad]; // 呼叫初始化視訊視窗函式 [self initViews]; // 後續步驟呼叫 Agora 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
// 匯入 UIKit
import UIKit
class ViewController: UIViewController {
...
// 定義 localView 變數
var localView: UIView!
// 定義 remoteView 變數
var remoteView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// 呼叫初始化視訊視窗函式
initView()
// 後續步驟呼叫 Agora 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. 實現視訊直播邏輯
現在,我們已經將 Agora iOS SDK 整合到專案中了。接下來我們要在 ViewController 中呼叫 Agora iOS SDK 提供的核心 API 實現基礎的視訊直播功能。你可以在Agora 在 GitHub 上提供開源的互動直播示例專案 OpenLive-iOS-Objective-C 與 OpenLive-iOS-Swift。在實現相關功能前,你可以下載並檢視原始碼。
API 呼叫時序見下圖:
按照以下步驟實現該邏輯:
a) 初始化AgoraRtcEngineKit物件 在呼叫其他 Agora API 前,需要建立並初始化 AgoraRtcEngineKit 物件。呼叫 sharedEngineWithAppId 方法,傳入獲取到的 App ID,即可初始化 AgoraRtcEngineKit 。
``` // Objective-C // 輸入 App ID 並初始化 AgoraRtcEngineKit 類。 - (void) viewDidLoad{ self.rtcEngine = [AgoraRtcEngineKit sharedEngineWithAppId:[KeyCenter AppId] delegate:self]; }
// 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 // 設定頻道場景為直播模式 [self.rtcEngine setChannelProfile:AgoraChannelProfileLiveBroadcasting];
// Swift // 設定頻道場景為直播模式 agoraKit.setChannelProfile(.liveBroadcasting) ```
c) 設定使用者角色 直播頻道有兩種使用者角色:主播和觀眾,其中預設的角色為觀眾。設定頻道場景為直播後,你可以在 app 中參考如下步驟設定使用者角色:
- 讓使用者選擇自己的角色是主播還是觀眾;
- 呼叫 setClientRole 方法,然後使用使用者選擇的角色進行傳參。
注意,直播頻道內的使用者,只能看到主播的畫面、聽到主播的聲音。加入頻道後,如果你想切換使用者角色,也可以呼叫 setClientRole 方法。
``` // 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 // 選擇使用者角色 @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 // 啟用視訊模組。 [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 // 啟用視訊模組。 agoraKit.enableVideo() // 設定本地檢視。 agoraKit.setupLocalVideo(videoCanvas)
// VideoSession部分 // VideoSession.swift hostingView = VideoView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) hostingView.translatesAutoresizingMaskIntoConstraints = false canvas = AgoraRtcVideoCanvas() canvas.uid = uid canvas.view = hostingView.videoView canvas.renderMode = .hidden ```
e) 加入頻道 頻道是人們在同一個視訊直播中的公共空間。完成初始化和設定本地檢視後(視訊直播場景),你就可以呼叫 joinChannelByToken 方法加入頻道。你需要在該方法中傳入如下引數:
- channelId: 傳入能標識頻道的頻道 ID。輸入頻道 ID 相同的使用者會進入同一個頻道。
- token: 傳入能標識使用者角色和許可權的 Token。你可以設定如下值: a) nil 。 b) 控制檯中生成的臨時 Token。一個臨時 Token 的有效期為 24 小時,詳情見獲取臨時 Token。 c) 你的伺服器端生成的正式 Token。適用於對安全要求較高的生產環境,詳情見生成 Token。若專案已啟用 App 證書,請使用 Token。 d) uid: 本地使用者的 ID。資料型別為整型,且頻道內每個使用者的 uid 必須是唯一的。若將 uid 設為 0,則 SDK 會自動分配一個 uid ,並在 joinSuccessBlock 回撥中報告。 e) joinSuccessBlock:成功加入頻道回撥。 joinSuccessBlock 優先順序高於 didJoinChannel ,2 個同時存在時, didJoinChannel 會被忽略。需要有 didJoinChannel 回撥時,請將 joinSuccessBlock 設定為 nil 。
更多的引數設定注意事項請參考 joinChannelByToken 介面中的引數描述。
``` // Objective-C // 加入頻道。 self.rtcEngine joinChannelByToken:[KeyCenter Token] channelId:self.roomName info:nil uid:0 joinSuccess:nil
// Swift // 加入頻道。 agoraKit.joinChannel(byToken: KeyCenter.Token, channelId: channelId, info: nil, uid: 0, joinSuccess: nil) ```
f) 設定遠端檢視 視訊互動直播中,通常你也需要看到其他主播。遠端主播成功加入頻道後,SDK 會觸發 didJoinedOfUid 回撥,該回調中會包含這個遠端主播的 uid 資訊。在該回調中呼叫 setupRemoteVideo 方法,傳入獲取到的 uid,設定遠端主播的檢視。
``` // 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 //需要在額外新增以下程式碼 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 // 離開頻道的步驟 - (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 // 離開頻道的步驟 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 物件,釋放 Agora SDK 使用的所有資源。
``` // Objective-C // 將以下程式碼填入你定義的函式中 [AgoraRtcEngineKit destroy];
// Swift // 將以下程式碼填入你定義的函式中 AgoraRtcEngineKit.destroy() ```
至此,完成,執行看看效果。拿兩部手機安裝編譯好的App,加入同一個頻道名,分別選擇主播角色和觀眾角色,如果2個手機都能看見同一個自己,說明你成功了。
如果你在開發過程中遇到問題,可以訪問論壇提問與聲網工程師交流(連結:https://rtcdeveloper.agora.io/) 1 也可以訪問後臺獲取更進一步的技術支援(連結:https://agora-ticket.agora.io/ 2 )
- 音訊技術的下一個“熱點”,會出現在哪個領域?丨一期一會 • 音訊工程師專場
- 桌面軟體開發框架大賞
- 即時通訊場景下安全合規的實踐和經驗
- 大家談的視訊體驗指標,都有哪些?如何測定?
- 使用 Agora 為Android APP新增視訊直播
- 使用 Agora 為Android APP新增視訊直播
- 基於 Agora SDK 實現 iOS 端的多人視訊互動
- 基於 Agora SDK 實現 Windows 端的多人視訊互動(基於3.6.2版本)
- 基於 Agora SDK 實現 Windows 端的一對一視訊通話(基於3.6.2版本)
- 從開源模型、框架到自研,聲網 Web 端虛擬背景演算法正式釋出
- 基於 Agora SDK 實現 iOS 端的多人視訊互動
- 從開源模型、框架到自研,聲網 Web 端虛擬背景演算法正式釋出
- 從開源模型、框架到自研,聲網 Web 端虛擬背景演算法正式釋出
- RTC 科普視訊丨聊聊空間音訊的原理與其背後的聲學原理
- RTC 科普視訊丨聊聊空間音訊的原理與其背後的聲學原理
- RTE NG-Lab:一起探索下一代實時互動新世界
- RTE NG-Lab:一起探索下一代實時互動新世界
- 開源規則引擎——ice:致力於解決靈活繁複的硬編碼問題
- 水晶球“通話調查”迎來四項升級 80%高頻質量問題可實現自助調查
- 開源規則引擎——ice:致力於解決靈活繁複的硬編碼問題