基於 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
  • 用例演示 - 創建實體 本節將演示一些示例用例並討論可選場景。 創建實體 從實體/聚合根類創建對象是實體生命周期的第一步。聚合/聚合根規則和最佳實踐部分 建議為Entity類創建一個主構造函數,以保證創建一個有效的實體。因此,無論何時我們需要創建實體的實例,我們都應該使用那個構造函數 參見下麵的問題 ...
  • 領域邏輯 & 應用邏輯 如前所述,領域驅動設計中的業務邏輯分為兩部分(層):領域邏輯和應用邏輯: 領域邏輯由系統的核心領域規則組成,應用邏輯實現應用特定的用例 雖然定義很明確,但實現起來可能並不容易。您可能無法決定哪些代碼應該位於應用程式層,哪些代碼應該位於領域層。本節試圖解釋其中的差異 多個應用程 ...
  • 表弟大學快畢業了,學了一個學期Python居然還不會寫學生管理系統,真的給我丟臉啊,教他又不肯學,還讓我直接給他寫,我真想兩巴掌上去,最終還是寫了給他,誰讓他是我表弟呢,關鍵時候還是得幫他一把! 寫完了放在那也是放著,所以今天分享給大家吧! 話不多說,咱們直接開始吧! 代碼解析 一、登錄頁面 1、定 ...
  • Zookeeper3.7源碼剖析 能力目標 掌握Zookeeper中Session的管理機制 能基於Client進行Debug測試Session創建/刷新操作 能搭建Zookeeper集群源碼配置 掌握集群環境下Leader選舉啟動過程 能說出Zookeeper選舉過程中的概念 能說出Zookeep ...
  • 前言 今天給大家分享一下我自己寫的筆記,純純的都是乾貨,關於字好像也能看。這是我學python整理出來的一些資料,希望對大家 有用。想要更多的資料那就的給一個關註了… python學習交流Q群:903971231### #導入Counter from collections import Count ...
  • Hi,大家好,我是Mic 一個工作5年的粉絲找到我。 他說: “Mic老師,你要是能回答出這個問題,我就佩服你” 我當場就懵了,現在打賭都這麼隨意了嗎? 我問他問題是什麼,他說“Kafka如何避免重覆消費的問題!” 下麵看看普通人和高手的回答! 普通人: Kafka怎麼避免重覆消費就是我們可以通過 ...
  • 前言 Steam是由美國電子游戲商Valve於2003年9月12日推出的數字發行平臺,被認為是電腦游戲界最大的數位發行平臺之一,Steam平臺是全球最大的綜合性數字發行平臺之一。玩家可以在該平臺購買、下載、討論、上傳和分享游戲和軟體。 而每周的steam會開啟了一輪特惠,可以讓游戲打折,而玩家就會 ...
  • 本篇內容將在上一篇已有的內容基礎上,進一步的聊一下項目中使用JPA的一些高階複雜場景的實踐指導,覆蓋了主要核心的JPA使用場景,可以讓你在需求開發的時候對JPA的使用更加的游刃有餘。 ...
  • 1.路徑處理 1.找模塊:sys.path import sys print(sys.path) - 1.理解 - 1.是python去查找包或模塊 - 2.項目開始根目錄,python內置的目錄 - 3.雖然說python的安裝目錄下也可以存放我們寫的模塊,但是不建議(太多了,不大好找) - 4. ...
  • Go 語言入門練手項目系列 01 基於命令行的圖書的增刪查改 02 文件管理 持續更新中... > 本文來自博客園,作者:Arway,轉載請註明原文鏈接:https://www.cnblogs.com/cenjw/p/gobeginner-proj-bookstore-cli.html 介紹 這是一 ...