基於 ZEGO SDK 實現 iOS 一對一音視頻聊天應用

来源:https://www.cnblogs.com/zegodeveloper/archive/2022/06/15/16377772.html
-Advertisement-
Play Games

在開始集成 ZEGO Express SDK 前,請確保開發環境滿足以下要求 ...


1 準備環境

在開始集成 ZEGO Express SDK 前,請確保開發環境滿足以下要求:

  • Xcode 12.0 或以上版本。
  • iOS 9.0 或以上版本且支持音視頻的 iOS 設備。
  • iOS 設備已經連接到 Internet。

2 項目準備

2.1 創建項目

進入即構官網,【ZEGO控制台】創建項目,並申請有效的 AppID,這一步很關鍵,appid為應用的唯一標識,如身份證號,是應用的身份證明,用於明確你的項目及組織身份。zego提供的服務也是基於APP ID;

2.2 Token 鑒權

  • 登錄房間時必須 使用 Token 鑒權 ,可參考 Token 鑒權教程
  • 為了方便開發階段的調試,開發者可直接在 ZEGO 控制台獲取臨時 Token(有效期為 24 小時) 來使用,詳情請參考 控制台(新版) - 項目管理 中的 “項目信息”。

3 集成

3.1 項目設置

開始集成前,可參考如下步驟設置你的項目;

如已有項目,本步驟可忽略。

如需新建項目,可按照以下步驟創建你的新項目:

  1. 啟動 Xcode,在 “Welcome to Xcode” 視窗中單擊 “Create a new Xcode project” 或選擇 “File > New > Project” 菜單。在出現的表單中,選擇 iOS 平臺,併在 “Application” 下選擇 “App”。

  2. 填寫表單並選取各個選項來配置項目,完成後,單擊 “Next”。
    必須提供 “Product Name” 和 “Organization Identifier”,用於創建 App 的唯一標識 “Bundle Identifier”。

  3. 選擇項目存儲路徑,單擊 “Create” 創建項目。

3.2 導入 SDK

使用 CocoaPods 自動集成

  1. 安裝 CocoaPods
  2. 打開終端,進入項目根目錄,執行 pod init 命令創建 Podfile 文件。
  3. 打開 Podfile 文件,在 “target” 下添加 po``d``'``Z``ego``E``xpress``Engine/V``ideo',需要將 “MyProject” 替換為開發者的 Target 名稱。
target 'MyProject' do
    use_frameworks!
    pod 'ZegoExpressEngine/Video'
end
  1. 執行 pod repo update 命令更新本地索引,確保能安裝最新版本的 SDK,最新版本號請參考 下載 SDK 包 中的發佈歷史。
  2. 執行 pod install 命令安裝 SDK。

4 實現流程

用戶通過 ZEGO Express SDK 進行視頻通話的基本流程為:

用戶 A、B 加入房間,用戶 B 預覽並將音視頻流推送到 ZEGO 雲服務(推流),用戶 A 收到用戶 B 推送音視頻流的通知之後,在通知中播放用戶 B 的音視頻流(拉流)。

整個音視頻通話推拉流過程的 API 調用時序如下圖:

4.1 初始化

1. 創建界面

根據場景需要,為你的項目創建視頻通話的用戶界面。我們推薦你在項目中添加如下元素:

  • 本地視頻視窗
  • 遠端視頻視窗
  • 結束通話按鈕

2.引入頭文件,準備基礎工作

// 引入 ZegoExpressEngine.h 頭文件
#import <ZegoExpressEngine/ZegoExpressEngine.h>

@interface ViewController ()<ZegoEventHandler>
//拉取播放其他用戶音視頻流的 view
@property (strong, nonatomic) UIView *remoteUserView;
//開始視頻通話的按鈕
@property (strong, nonatomic) UIButton *startVideoTalkButton;
//停止視頻通話的按鈕
@property (strong, nonatomic) UIButton *stopVideoTalkButton;

@end
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupUI];
}

- (void)setupUI {
    self.remoteUserView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 180, 250)];
    self.remoteUserView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:self.remoteUserView];

    self.startVideoTalkButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.view addSubview:self.startVideoTalkButton];
    self.startVideoTalkButton.frame = CGRectMake(100, self.view.bounds.size.height - 280, 150, 50);
    [self.startVideoTalkButton.titleLabel setFont:[UIFont systemFontOfSize:32]];
    [self.startVideoTalkButton setTitle:@"開始通話" forState:UIControlStateNormal];
    [self.startVideoTalkButton addTarget:self action:@selector(startVideoTalk:) forControlEvents:UIControlEventTouchUpInside];

    self.stopVideoTalkButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.view addSubview:self.stopVideoTalkButton];
    self.stopVideoTalkButton.frame = CGRectMake(100, self.view.bounds.size.height - 200, 150, 50);
    [self.stopVideoTalkButton.titleLabel setFont:[UIFont systemFontOfSize:32]];
    [self.stopVideoTalkButton setTitle:@"停止通話" forState:UIControlStateNormal];
    [self.stopVideoTalkButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [self.stopVideoTalkButton addTarget:self action:@selector(stopVideoTalk:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)startVideoTalk:(UIButton *)button {
    [self createEngine];
    [self loginRoom];
    [self startPublish];
}

3. 創建引擎

調用 createEngineWithProfile 介面,將申請到的 AppID 傳入參數 “appID”,創建引擎單例對象。

註冊回調,可將實現了 ZegoEventHandler 的對象(例如 “self”)傳入參數 “eventHandler”。

- (void)createEngine {
    ZegoEngineProfile *profile = [[ZegoEngineProfile alloc] init];
    // 請通過官網註冊獲取,格式為:1234567890
    profile.appID = <#appID#>;
    //通用場景接入
    profile.scenario = ZegoScenarioGeneral;
    // 創建引擎,並註冊 self 為 eventHandler 回調。不需要註冊回調的話,eventHandler 參數可以傳 nil,後續可調用 "-setEventHandler:" 方法設置回調
    [ZegoExpressEngine createEngineWithProfile:profile eventHandler:self];
}

6.2 登錄房間

調用 loginRoom 介面登錄房間。roomID 和 user 的參數由您本地生成,但是需要滿足以下條件:

  • 同一個 AppID 內,需保證 “roomID” 全局唯一。
  • 同一個 AppID 內,需保證 “userID” 全局唯一,建議開發者將 “userID” 與自己業務的賬號系統進行關聯。
- (void)loginRoom {
    // roomID 由您本地生成,需保證 “roomID” 全局唯一。不同用戶要登陸同一個房間才能進行通話
    NSString *roomID = @"room1";
    // 創建用戶對象,ZegoUser 的構造方法 userWithUserID 會將 “userName” 設為與傳的參數 “userID” 一樣。“userID” 與 “userName” 不能為 “nil”,否則會導致登錄房間失敗。
    // userID 由您本地生成,需保證 “userID” 全局唯一。
    ZegoUser *user = [ZegoUser userWithUserID:@"user1"];
    // 只有傳入 “isUserStatusNotify” 參數取值為 “true” 的 ZegoRoomConfig,才能收到 onRoomUserUpdate 回調。
    ZegoRoomConfig *roomConfig = [[ZegoRoomConfig alloc] init];
    //token 由用戶自己的服務端生成,為了更快跑通流程,也可以通過即構控制台 https://console.zego.im/dashboard 獲取臨時的音視頻 token
    roomConfig.token = @"<#token#>";
    roomConfig.isUserStatusNotify = YES;
    // 登錄房間
    [[ZegoExpressEngine sharedEngine] loginRoom:roomID user:user config:roomConfig callback:^(int errorCode, NSDictionary * _Nullable extendedData) {
        // (可選回調) 登錄房間結果,如果僅關註登錄結果,關註此回調即可
        if (errorCode == 0) {
            NSLog(@"房間登錄成功");
        } else {
            // 登錄失敗,請參考 errorCode 說明 https://doc-zh.zego.im/article/4377
            NSLog(@"房間登錄失敗");
        }
    }];
}

登錄狀態(房間連接狀態)回調

調用登錄房間介面之後,您可通過監聽 onRoomStateUpdate 回調實時監控自己在本房間內的連接狀態。

3.3 預覽自己的畫面,並推送到 ZEGO 音視頻雲

1. 預覽自己的畫面

如果希望看到本端的畫面,可調用 startPreview 介面設置預覽視圖,並啟動本地預覽。

2. 將自己的音視頻流推送到 ZEGO 音視頻雲

在用戶調用 loginRoom 介面後,可以直接調用 startPublishingStream 介面,傳入 “streamID”,將自己的音視頻流推送到 ZEGO 音視頻雲。您可通過監聽 onPublisherStateUpdate 回調知曉推流是否成功。

“streamID” 由您本地生成,但是需要保證:

同一個 AppID 下,“streamID” 全局唯一。如果同一個 AppID 下,不同用戶各推了一條 “streamID” 相同的流,後推流的用戶推流失敗。

- (void)startPublish {
    // 設置本地預覽視圖並啟動預覽,視圖模式採用 SDK 預設的模式,等比縮放填充整個 View
    [[ZegoExpressEngine sharedEngine] startPreview:[ZegoCanvas canvasWithView:self.view]];
    // 用戶調用 loginRoom 之後再調用此介面進行推流
    // 在同一個 AppID 下,開發者需要保證 “streamID” 全局唯一,如果不同用戶各推了一條 “streamID” 相同的流,後推流的用戶會推流失敗。
    [[ZegoExpressEngine sharedEngine] startPublishingStream:@"stream1"];
}

3.4 拉取其他用戶的音視頻

進行視頻通話時,我們需要拉取到其他用戶的音視頻。

在同一房間內的其他用戶將音視頻流推送到 ZEGO 音視頻雲時,我們會在 onRoomStreamUpdate 回調中收到音視頻流新增的通知,並可以通過 ZegoStream 獲取到某條流的 “streamID”。

我們可以在該回調中,調用 startPlayingStream ,傳入 “streamID” 拉取拉取播放該用戶的音視頻。您可通過監聽 onPlayerStateUpdate 回調知曉是否成功拉取音視頻。

// 房間內其他用戶推流/停止推流時,我們會在這裡收到相應流增減的通知
- (void)onRoomStreamUpdate:(ZegoUpdateType)updateType streamList:(NSArray<ZegoStream *> *)streamList extendedData:(NSDictionary *)extendedData roomID:(NSString *)roomID {
    //當 updateType 為 ZegoUpdateTypeAdd 時,代表有音視頻流新增,此時我們可以調用 startPlayingStream 介面拉取播放該音視頻流
    if (updateType == ZegoUpdateTypeAdd) {
        // 開始拉流,設置遠端拉流渲染視圖,視圖模式採用 SDK 預設的模式,等比縮放填充整個View
        // 如下 remoteUserView 為 UI 界面上 View.這裡為了使示例代碼更加簡潔,我們只拉取新增的音視頻流列表中第的第一條流,在實際的業務中,建議開發者迴圈遍歷 streamList ,拉取每一條音視頻流
        NSString *streamID = streamList[0].streamID;
        [[ZegoExpressEngine sharedEngine] startPlayingStream:streamID canvas:[ZegoCanvas canvasWithView:self.remoteUserView]];
    }
}

7 運行效果

音視頻的基礎功能已完成,接下來我們運行下效果,1步快速檢驗成果。

step1 , 與好友一起安裝編譯好的App,在手機上可以看到對方併進行通話互動。

完成以上,說明你成功啦!

Enjoy與好友的歡樂時光!

獲取更多文檔、Demo、技術幫助

獲取本文的Demo、開發文檔、技術支持。
獲取SDK的商務活動、熱門產品。
註冊即構ZEGO開發者帳號,快速開始。

音視頻場景解決方案分享,更多詳情可搜索官網(https://zegoguanwang.datasink.sensorsdata.cn/t/pB)
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文介紹 SQL 如何使用內聯結(INNER JOIN)、外聯結(OUTER JOIN)和交叉聯結(CROSS JOIN)。簡單來說,就是將其他表中的列添加過來,進行“添加列”的運算。 本文重點 聯結(JOIN)就是將其他表中的列添加過來,進行“添加列”的集合運算。UNION 是以行(縱向)為單位進 ...
  • 導讀: 本文主要介紹嗶哩嗶哩在數據湖與數據倉庫一體架構下,探索查詢加速以及索引增強的一些實踐。主要內容包括: 什麼是湖倉一體架構 嗶哩嗶哩目前的湖倉一體架構 湖倉一體架構下,數據的排序組織優化 湖倉一體架構下,索引增強與優化的實踐探索 -- 01 什麼是湖倉一體 當我們講湖倉一體時,涉及到數據湖和數 ...
  • 原文鏈接:實時開發平臺建設實踐,深入釋放實時數據價值 視頻回顧:點擊這裡 課件獲取:點擊這裡 一、實時數倉建設背景 隨著整體行業的數字化轉型不斷深入以及技術能力的不斷提高,傳統的 T+1 式(隔日)的離線大數據模式越來越無法滿足新興業務的發展需求,開展實時化的大數據業務,是企業深入挖掘數據價值的一條 ...
  • 本文將會和大家一起學習集合運算操作。集合在數學領域表示“(各種各樣的)事物的總和”,在資料庫領域表示記錄的集合。具體來說,表、視圖和查詢的執行結果都是記錄的集合。 本文重點 集合運算就是對滿足同一規則的記錄進行的加減等四則運算。 使用 UNION(並集)、INTERSECT(交集)、EXCEPT(差 ...
  • Redis緩存更新策略 本文整理自黑馬程式員相關資料 記憶體淘汰 超時剔除 主動更新 說明 不用自己維護,利用Redis的記憶體淘汰機制,當記憶體不足時自動淘汰部分數據。下次查詢時更新緩存 給緩存數據添加TTL時間,到期後自動刪除緩存,下次查詢時更新緩存 編寫業務邏輯,在修改數據的同時,更新緩存 一致性 ...
  • 一、課程介紹 數據服務API作為數據統一服務平臺建設的最上層,能夠將數據倉庫數據以服務化、介面化的方式提供給數據使用方,屏蔽底層數據存儲、計算的諸多細節,簡化和加強數據的使用。 隨著企業“互聯網化、數字化”進程的不斷深入,越來越多的業務被遷移到互聯網上,產生大量的業務交互和對外服務需求,對API介面 ...
  • 一、包的作用 • Oracle中包的概念與Java中包的概念非常類似,只是Java中的包是為了分類管理類,但是關鍵字都是package。 • 在一個大型項目中,可能有很多模塊,而每個模塊又有自己的過程、函數等。而這些過程、函數預設是放在一起的(如在PL/SQL中,過程預設都是放在一起的,即Proce ...
  • 一、android工程配置 buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.4' } } apply plugin: 'com.android. ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...