雲信小課堂|如何實現音視頻通話


 

image.png

大家好,歡迎大家來到「雲信小課堂 」。

本欄目致力於解答有關 IM 和音視頻的一切問題,產品特點、使用場景、技術名詞、接入指南、功能實現......歡迎大家留言提問,我們每節課會選取大家感興趣的問題進行解答。

概述

微信的火熱讓網絡語音/視頻通話逐步替代了傳統手機通話,那么如果快速實現一款輕量的音視頻通話應用呢?其實並不復雜,幾十行代碼就能實現。

開學第一課,我們一起聊一聊如何快速實現音視頻通話。

功能解析

我們先來定義一下一款輕量的音視頻通話應用需要哪些功能,首先基礎類功能可能包含

  • 加入/離開通話
  • 語音/視頻通話
  • 音頻/視頻開啟與關閉

 

具體可參見下圖,當然在基礎類功能之上我們也可以引入美顏、變聲等更多高級的玩法,本期暫不做展開,后面會陸續為大家介紹哦!

 

1.png

 

功能實現

本章以  iOS 為例介紹如何使用 NERTC SDK 實現音視頻通話,更多終端參見網易雲信官方 Github

以下內容為大家介紹如果基於 網易雲信 音視頻通話2.0 SDK 快速實現音視頻通話功能,基本步驟如下:

  1. 集成SDK(網易雲信音視頻2.0 SDK)
  2. 設置本地視圖
  3. 加入頻道
  4. 設置遠端視圖
  5. 音頻流
  6. 離開頻道
  7. 銷毀音視頻實例

集成 SDK

CocoaPods 集成

集成前,請先前往SDK下載頁面查看當前最新版本,並查詢本地倉庫中對應的版本是否為最新版本。若不是最新版本,建議先更新本地倉庫,以確保可以集成最新的SDK版本。

pod search NERtcSDK      //本地倉庫中查詢 NERtcSDK 信息    
pod repo update          //更新本地倉庫    
pod install              //執行安裝

至此, NERTC SDK 已經導入完成。

手動導入 SDK 集成

  • 請先前往 SDK 下載頁獲取當前最新版本;
  • 將解壓得到的 NERtcSDK.framework 和 NMCBasicModuleFramework.framework 文件拷貝到工程項目文件夾下;
  • 以 Xcode Version 11.5 為例,進入TARGETS > Project Name > General > Frameworks, Libraries, and Embedded Content 菜單,點擊 +,再點擊 Add Other…,將上述解壓得到的 SDK 文件添加進去。同時,將 Embed 屬性設置為 Embed & Sign,以使得 SDK 動態庫和應用簽名保持一致;

至此, NERTC SDK 已經導入完成。

實現音視頻通話

本節以 iOS 為例介紹如何使用 NERTC SDK 實現音視頻通話,主要流程如下圖所示:

(更多終端參見網易雲信官方 Github

2.png

3.png

*此處 Server 指的是雲信 SDK Sever。

 

初始化

  • 引入頭文件
#import <NERtcSDK/NERtcSDK.h>
  • 執行初始化
@interface  Myapp () 
...NERtcEngine coreEngine = [NERtcEngine sharedEngine];NERtcEngineContext context = [[NERtcEngineContext alloc] init];
context.engineDelegate = self;
context.appKey = AppKey;
[coreEngine setupEngineWithContext:context];
...

初始化的參數類 NERtcEngineContext 屬性說明:

@interface NERtcEngineContext : NSObject
/**
 已開通音視頻功能的雲信應用的AppKey。
 */@property (nonatomic, copy) NSString *appKey;
/**
 log的相關設置,由開發者提供。可選參數。
 */@property (nonatomic, strong) NERtcLogSetting *logSetting;
/**
 通話相關信息的回調接口,由開發者提供。
 */@property (nonatomic, weak) id<NERtcEngineDelegateEx> engineDelegate;
@end

設置本地視圖

啟動視頻流

  • API 描述
@protocol INERtcEngine <NSObject>/**
 開啟自己的視頻。可以在加入頻道前和頻道后調用。

 @param enabled 是否開啟
 @return 操作返回值,成功則返回 0
*/
- (int)enableLocalVideo:(BOOL)enabled;@end
  • 示例代碼
[NERtcEngine.sharedEngine enableLocalVideo:YES]; 

設置本地視頻畫布

啟動視頻流后,可以設置本地視頻畫布,用來顯示本地采集的視頻畫面。

  • API 描述
@protocol INERtcEngine <NSObject>/**
 設置本地視頻畫布

 @param canvas 視頻窗口,如果需要刪除則傳 nil
 @return 操作返回值,成功則返回 0
 */
- (int)setupLocalVideoCanvas:(NERtcVideoCanvas *)canvas;@end
  • 示例代碼
NERtcVideoCanvas *canvas = [[NERtcVideoCanvas alloc] init];
canvas.container = self.localUserView;[NERtcEngine.sharedEngine setupLocalVideoCanvas:canvas];

設置成功后,即可顯示本地視頻畫面。

加入頻道

加入頻道前,請確保已完成初始化相關事項。若您的業務中涉及呼叫邀請等機制,可以使用信令。

  • API 描述
@protocol INERtcEngine <NSObject>/**
加入頻道
 @param token 頻道token
 @param channelName 頻道名
 @param uId 當前用戶的Id
 @param completion 操作完成的 block 回調
 @return 操作返回值,被執行了則返回 0
 */
- (int)joinChannelWithToken:(NSString *)token                channelName:(nullable NSString *)channelName                      myUid:(uint64_t)uId                 completion:(NERtcJoinChannelCompletion)completion;@end
  • 參數說明
    • token:頻道 token。支持傳入以下內容:
      • 空字符串。該種方式需要先開通非安全模式。安全性不高,建議在產品正式上線前轉為安全模式;
      • 安全認證簽名密鑰。安全模式下必需。若未傳入正確的 token 將無法進入頻道。建議使用安全模式;
    • channelName:頻道名稱,傳入相同頻道名稱的用戶會進入同一個通話頻道;
    • UID:用戶的唯一標識 Id,頻道內每個用戶的 UID 必須是唯一的;

 

  • 示例代碼
//加入房間
- (void)joinChannelWithRoomId:(NSString *)roomId
                       userId:(uint64_t)userId {
    __weak typeof(self) weakSelf = self;
    [NERtcEngine.sharedEngine joinChannelWithToken:@""
                                       channelName:roomId
                                             myUid:userId
                                        completion:^(NSError * _Nullable error, uint64_tchannelId, uint64_t elapesd) {
        if (error) {
            //加入失敗了,彈框之后退出當前頁面
        } else {
            //加入成功
        }
    }];
} 

設置遠端視圖

視頻通話過程中,除了要顯示本地的視頻畫面,通常也要顯示參與通話的其他用戶的遠端視頻畫面。

監聽遠端用戶進出頻道

  • API 描述
@protocol NERtcEngineDelegate <NSObject>/**
 其他用戶加入頻道的回調

 @param userID 用戶的id
 @param userName 用戶名稱
 */
- (void)onNERtcEngineUserDidJoinWithUserID:(uint64_t)userID                                   userName:(NSString *)userName;
/**
 其他用戶離開頻道的回調

 @param userID 用戶的id
 @param reason 離開的原因
 */
- (void)onNERtcEngineUserDidLeaveWithUserID:(uint64_t)userID   


設置遠端視頻畫布

 

監聽到遠端用戶加入頻道后,可以設置遠端視頻畫布,用來顯示遠端用戶的視頻畫面。

  • API 描述
@protocol INERtcEngine <NSObject>
/**
 設置遠端的視頻播放窗口
 只能在加入頻道后調用

 @param userID 用戶的id
 @param canvas 視頻窗口,如果需要刪除則傳nil
 @return 操作返回值,成功則返回 0
 */
- (int)setupRemoteVideoCanvas:(NERtcVideoCanvas *)canvas forUserID:(uint64_t)userID;@end

 

  • 示例代碼
- (void)onNERtcEngineUserDidJoinWithUserID:(uint64_t)userID                                  userName:(NSString *)userName {

    //如果已經setup了一個遠端的canvas,則不需要再建立了
    ...
    if (_remoteCanvas != nil) {
        return;
    }

    //建立遠端canvas,用來渲染遠端畫面
    NERtcVideoCanvas *canvas = [self setupRemoteCanvasWithUid:userID];
    [NERtcEngine.sharedEngine setupRemoteVideoCanvas:canvas                                           forUserID:userID];
    ...
}

···

- (void)onNERtcEngineUserDidLeaveWithUserID:(uint64_t)userID                                     reason:(NERtcSessionLeaveReason)reason {


    //如果遠端的人離開了,重置遠端模型和UI
    ...
    [NERtcEngine.sharedEngine setupRemoteVideoCanvas:nil                                           forUserID:userID];
    ...
}

 

監聽遠端視頻流發布

當頻道中的其他用戶有視頻流發出/關閉時,分別會走入以下回調:

  • API 描述
@protocol NERtcEngineDelegate <NSObject>
/**
 其他用戶打開視頻的回調

 @param userID 用戶id
 @param profile 用戶發送視頻的最大分辨率類型
 */
- (void)onNERtcEngineUserVideoDidStartWithUserID:(uint64_t)userID videoProfile:(NERtcVideoProfileType)profile;
/**
 其他用戶關閉視頻的回調

 @param userID 用戶id
 */
- (void)onNERtcEngineUserVideoDidStop:(uint64_t)userID;@end

  

訂閱遠端視頻流

 

在設置完遠端視頻畫布后,且監聽到遠端用戶有視頻發布時,可以訂閱遠端用戶的視頻流。

 

  • API 描述
@protocol  INERtcEngineEx /**
訂閱或取消訂閱別人的視頻,訂閱了才會接收別人的視頻數據。
@param  subscribe 是否訂閱 
@param  userID 用戶的id 
@param  streamType 訂閱的遠端視頻流類型 
@return  操作返回值,成功則返回 0 
*/
- (int)subscribeRemoteVideo:(BOOL)subscribe                   forUserID:(uint64_t)userID                  streamType:(NERtcRemoteVideoStreamType)streamType;@end

 

  • 示例代碼
// 監聽到遠端用戶有視頻流發布
- (void)onNERtcEngineUserVideoDidStartWithUserID:(uint64_t)userID
                                    videoProfile:(NERtcVideoProfileType)profile {
    //如果已經訂閱過遠端視頻流,則不需要再訂閱了
    ...
    if (_remoteCanvas.subscribedVideo) {
        return;
    }


    //訂閱遠端視頻流。
    _remoteCanvas.subscribedVideo = YES;
    [NERtcEngine.sharedEngine subscribeRemoteVideo:YES
                                 forUserID:userID
                                streamType:kNERtcRemoteVideoStreamTypeHigh];
    ...}
// 監聽到遠端用戶停止視頻流發布
- (void)onNERtcEngineUserVideoDidStop:(uint64_t)userID {
    if (userID == _remoteCanvas.uid) {
        // 收到此回調后,SDK 內部會取消對應的視頻流訂閱,無需開發者主動取消訂閱。
        ...
        _remoteStatLab.hidden = YES;
        ...
    }
}

 

訂閱成功后,即可顯示遠端的視頻畫面。

音頻流

在 NERtcSDK 中,本地音頻的采集發布和遠端音頻訂閱播放是默認啟動的,正常情況下無需開發者主動干預。

離開頻道

當通話結束,需要離開頻道,可以調用以下接口:

  • API 描述
@protocol INERtcEngine <NSObject>
/**
 離開頻道

 @return 操作返回值,成功則返回 0
 */
- (int)leaveChannel;@end
  • 示例代碼
//UI 掛斷按鈕事件- (IBAction)onHungupAction:(UIButton *)sender {
    [NERtcEngine.sharedEngine leaveChannel];
    [self dismiss];
}

執行完 leaveChannel 方法后,SDK 會觸發 離開頻道回調通知開發者:

  • API 描述
@protocol NERtcEngineDelegate <NSObject>/**
 離開頻道回調

 @param result 離開的結果
 */
- (void)onNERtcEngineDidLeaveChannelWithResult:(NERtcError)result;@end
  • 示例代碼
- (void)onNERtcEngineDidLeaveChannelWithResult:(NERtcError)result{
    // 進行業務數據清理
}

銷毀音視頻實例

釋放當前的 NERtcEngine 實例,建議在 App 確定不再需要使用 NERtcEngine 實例時,通過該接口釋放 NERtcEngine 實例的對象資源。

  • API 描述
@interface NERtcEngine : NSObject <INERtcEngineEx>
/**
 釋放當前的 NERtcEngine 實例
 建議在 App 確定不再需要使用 NERtcEngine 實例時,通過該接口釋放 NERtcEngine 實例的對象資源;
 1. 該接口的工作方式為同步調用方式,必須在子線程中才能調用,否則會調用失敗;如:
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{     [NERtcEngine destroyEngine];
 }); 2. 該接口不得在 SDK 的回調中調用,在接口返回前也不允許調用 SDK 的其他任何接口;3. 接口調用返回之后,如果需要再次使用 SDK,可以重新調用 sharedEngine 來獲取一個新的 NERtcEngine 實例。

 */

+ (int)destroyEngine;@end
  • 示例代碼
- (void)dealloc {
    [NERtcEngine destroyEngine]; //銷毀實例
}

 

示例項目

為了便於大家學習理解,我們將上文內容作為開源項目發布在了 Github 上,各位有興趣可以前往查看示例項目。

 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM