雲信小課堂|如何實現音視訊通話
大家好,歡迎大家來到「雲信小課堂 」。
本欄目致力於解答有關 IM 和音視訊的一切問題,產品特點、使用場景、技術名詞、接入指南、功能實現......歡迎大家留言提問,我們每節課會選取大家感興趣的問題進行解答。
概述
微信的火熱讓網路語音/視訊通話逐步替代了傳統手機通話,那麼如果快速實現一款輕量的音視訊通話應用呢?其實並不複雜,幾十行程式碼就能實現。
開學第一課,我們一起聊一聊如何快速實現音視訊通話。
功能解析
我們先來定義一下一款輕量的音視訊通話應用需要哪些功能,首先基礎類功能可能包含
- 加入/離開通話
- 語音/視訊通話
- 音訊/視訊開啟與關閉
具體可參見下圖,當然在基礎類功能之上我們也可以引入美顏、變聲等更多高階的玩法,本期暫不做展開,後面會陸續為大家介紹哦!
功能實現
本章以 iOS 為例介紹如何使用 NERTC SDK 實現音視訊通話,更多終端參見網易雲信官方 Github
以下內容為大家介紹如果基於 網易雲信 音視訊通話2.0 SDK 快速實現音視訊通話功能,基本步驟如下:
- 整合SDK(網易雲信音視訊2.0 SDK)
- 設定本地檢視
- 加入頻道
- 設定遠端檢視
- 音訊流
- 離開頻道
- 銷燬音視訊例項
整合 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)
*此處 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 上,各位有興趣可以前往檢視示例專案。
&nbs