Unity 語音和視頻通話快速解決方案——聲網 SDK接入指南(Android)
一、前言
當前游戲為了增加社互動動和代入感,比如狼人殺、團隊競技游戲等,經常會產生需要實時語音和視頻通話的需求,但是對于個人開發者和小團隊,這種需要前后端配合,重網路的開發需求會帶來很大的挑戰,
為此我們需要尋找一個成熟、可靠的解決方案,每個月提供 10000 分鐘免費使用時長的聲網 Agora成為了我的最佳選擇,并且聲網的 SDK(Software Development Kit) 包體積很小,運行時CPU和記憶體占用率低,對于移動端的游戲開發很友好,2019年7月聲網正式成為了 Unity 官方認證合作伙伴,語音和視頻的 SDK 也已經發布在了 Unity 資源商店中,能夠非常方便的接入,
注意:語音和視頻的包有沖突,不兼容(一些庫和平臺配置不同,可以自己手動修改),請根據需求,第四步和第五步二選一,引擎支持開關視頻和聲音,所以可以接入視頻 SDK 包,關閉視頻,僅僅使用語音通話,
二、后臺創建應用
為了方便后續接入操作,這里先注冊和登錄到 官方后臺 創建應用,獲取我們之后需要的 App ID,可以根據官網的新手引導來創建應用,也可以參考如下步驟,
輸入專案名稱,目前暫時使用 APP ID 的鑒權模式,后續根據需要也可以在專案編輯界面切換到 Token 鑒權模式,該模式更加安全,生成 Token 程式需要搭建在服務器上,可以參考官方檔案,
創建成功后,我們點擊 APP ID 下的顯示按鈕,APPID 就會復制到粘貼板,
三、獲取 SDK
這里我使用的 Unity 版本為 2019.3.14,進入商店我們搜索 Agora,可以發現視頻和語音兩個 SDK 包,
如果打不開 Unity Store 的同學還可以從官網開發者中心下載,
四、接入 Agora Voice 語音 SDK
1. 匯入工程
從 Asset Store 的我的資源(My Asset)中找到我們下載的 Agora Voice SDK For Unity ,點擊 Import 匯入到工程中,
匯入的檔案結構如下,
- Demo:官方提供的測驗語音 Demo
- Edior:iOS 構建后處理腳本
- Plugins:不同平臺所依賴的庫
- Scripts:SDK 原始碼
2. 搭建測驗場景
為了驗證 Agora Voice 的效果,我們打開官方的 Demo,或者是自己搭建一個類似的簡單場景,主要有三個按鈕,分別用來測驗加入頻道、離開頻道和靜音,
3. 申請麥克風權限
在 Unity 2018.3 版本以后的新版本中,需要我們主動申請麥克風權限,
#if(UNITY_2018_3_OR_NEWER)
using UnityEngine.Android;
#endif
// ...
private void PermissionRequest()
{
#if (UNITY_2018_3_OR_NEWER)
if (!Permission.HasUserAuthorizedPermission(Permission.Microphone)) // 判斷是否有麥克風權限
{
Permission.RequestUserPermission(Permission.Microphone); // 申請麥克風權限
}
#endif
}
// ...
4. 初始化 IRtcEngine
我們在呼叫 Agora 的介面前,需要先初始化 IRtcEngine,此時我們第二步獲取的 APP ID,就在這里派上用處了,在通過 APP ID 創建 IRtcEngine 后,可以根據需求增加回呼事件,這里我接入了一些比較常用的回呼,
using agora_gaming_rtc;
// ...
private IRtcEngine mRtcEngine = null;
public const string APP_ID = "你自己的應用 APP ID";
private void InitEngine()
{
// 通過 APP ID 創建
mRtcEngine = IRtcEngine.GetEngine(APP_ID);
// 加入頻道成功后的回呼
// channelName:頻道名稱
// uid:用戶ID(發起請求時候如果沒有指定,服務器會自動分配一個)
// elapsed:從本地用戶呼叫 JoinChannelByKey 到該回呼觸發的延遲(毫秒),
mRtcEngine.OnJoinChannelSuccess += (string channelName, uint uid, int elapsed) =>
{
// ...
};
// 離開頻道的回呼
// stats:通話統計的資料
// duration:通話時長
// txBytes:發送位元組數(bytes)
// rxBytes:接收位元組數(bytes)
// txKBitRate:發送碼率(kbps)
// rxKBitRate:接收碼率(kbps)
mRtcEngine.OnLeaveChannel += (RtcStats stats) =>
{
string leaveChannelMessage = string.Format("onLeaveChannel callback duration {0}, tx: {1}, rx: {2}, tx kbps: {3}, rx kbps: {4}", stats.duration, stats.txBytes, stats.rxBytes, stats.txKBitRate, stats.rxKBitRate);
// ...
};
// 用戶加入回呼
// uid:新加入頻道的遠端用戶/主播 ID
// elapsed:從本地用戶呼叫 JoinChannelByKey 到該回呼觸發的延遲(毫秒),
mRtcEngine.OnUserJoined += (uint uid, int elapsed) =>
{
// ...
};
// 用戶離開回呼
// uid:離線用戶或主播的用戶 ID
// reason:離線原因(主動離開、超時、直播模式身份切換)
mRtcEngine.OnUserOffline += (uint uid, USER_OFFLINE_REASON reason) =>
{
string userOfflineMessage = string.Format("onUserOffline callback uid {0} {1}", uid, reason);
Debug.Log(userOfflineMessage);
};
// 提示頻道內誰在說話
// speakers:說話人資訊
// speakerNumber:說話人數[0,3]
// totalVolume:總音量
mRtcEngine.OnVolumeIndication += (AudioVolumeInfo[] speakers, int speakerNumber, int totalVolume) =>
{
// ...
};
// 用戶靜音提示回呼
// uid:用戶 ID
// muted:是否靜音
mRtcEngine.OnUserMutedAudio += (uint uid, bool muted) =>
{
// ...
};
// 發生警告回呼
mRtcEngine.OnWarning += (int warn, string msg) =>
{
// ...
};
// 發生錯誤回呼
mRtcEngine.OnError += (int error, string msg) =>
{
// ...
};
// 當前通話統計回呼,每兩秒觸發一次,
mRtcEngine.OnRtcStats += (RtcStats stats) =>
{
// ...
};
// 語音路由已發生變化回呼,(只在移動平臺生效)
mRtcEngine.OnAudioRouteChanged += (AUDIO_ROUTE route) =>
{
// ...
};
// Token 過期回呼
mRtcEngine.OnRequestToken += () =>
{
// ...
};
// 網路中斷回呼(建立成功后才會觸發)
mRtcEngine.OnConnectionInterrupted += () =>
{
// ...
};
// 網路連接丟失回呼
mRtcEngine.OnConnectionLost += () =>
{
// ...
};
// 設定 Log 級別
mRtcEngine.SetLogFilter(LOG_FILTER.INFO);
// 設定為自由說話模式,常用于一對一或者群聊
mRtcEngine.SetChannelProfile(CHANNEL_PROFILE.CHANNEL_PROFILE_COMMUNICATION);
}
...
5. 常用 API
5.1 加入頻道
public void JoinChannel()
{
// 從界面的輸入框獲取頻道名稱
string channelName = mChannelNameInputField.text.Trim();
Debug.Log(string.Format("tap joinChannel with channel name {0}", channelName));
if (string.IsNullOrEmpty(channelName))
{
return;
}
// 加入頻道
// channelKey: 動態秘鑰,我們最開始沒有選擇 Token 模式,這里就可以傳入 null;否則需要傳入服務器生成的 Token
// channelName: 頻道名稱
// info: 開發者附帶資訊(非必要),不會傳遞給頻道內其他用戶
// uid: 用戶ID,0 為自動分配
mRtcEngine.JoinChannelByKey(channelKey: null, channelName: channelName, info:"extra",uid: 0);
}
5.2 靜音
void MuteButtonTapped()
{
string labeltext = isMuted ? "靜音" : "取消靜音";
Text label = muteButton.GetComponentInChildren<Text>();
if (label != null)
{
label.text = labeltext;
}
isMuted = !isMuted;
// 設定靜音(停止推送本地音頻)
mRtcEngine.MuteLocalAudioStream(!isMuted);
}
5.3 離開頻道 & 銷毀 IRtcEngine
public void LeaveChannel()
{
// 離開頻道
mRtcEngine.LeaveChannel();
string channelName = mChannelNameInputField.text.Trim();
Debug.Log(string.Format("left channel name {0}", channelName));
}
void OnApplicationQuit()
{
if (mRtcEngine != null)
{
// 銷毀 IRtcEngine
IRtcEngine.Destroy();
mRtcEngine = null;
}
}
6. 最終效果
我們可以先在編輯器上驗證,能夠正常運行后,將平臺切換到 Android 后,直接出包就行,Agora SDK 中已經提供了 Android 中所需要的庫,
最后運行在 Android 上的效果如下:
- 輸入1234 成功加入頻道,分配給我們用戶 id:1186284123
- 有其他用戶加入,用戶id:2996662973
- 用戶id:2996662973 開啟靜音
- 用戶id:2996662973 離開頻道
- 我們離開頻道,顯示通話統計資料
語音通話的 API 時序圖如下:
五、接入 Agora Video 視頻 SDK
1. 匯入工程
如果你按照第五步匯入過音頻了,這里類似直接從商店匯入 Agora Video SDK,要注意的是兩個包的內容不同,當然兩個 SDK 包的本質還是相同的,只是不同平臺中的配置相關有些不同,如果同時使用,會出現問題,有能力的同學也可以嘗試修改兼容,這里還是比較推薦直接洗掉音頻 Voice 的包,再匯入新的 Video 的包,這樣就不用我們費盡的設定不同平臺配置了,
2. 搭建測驗場景
同樣的我們可以直接使用Demo 中提供的場景,SceneHome 是啟動場景,在最后測驗的時候,注意需要修改 Build Setting 中場景串列,或者可以搭建一個簡易如下的場景,
3. 申請麥克風+相機權限
與音頻不同,視頻需要我們添加相機權限的申請,
private void PermissionRequest () {
#if (UNITY_2018_3_OR_NEWER)
if (!Permission.HasUserAuthorizedPermission (Permission.Microphone)) {
Permission.RequestUserPermission (Permission.Microphone);
}
// 增加相機權限
if (!Permission.HasUserAuthorizedPermission (Permission.Camera)) {
Permission.RequestUserPermission (Permission.Camera);
}
#endif
}
4. 初始化 IRtcEngine
與音頻唯一不同的是需要打開視頻功能,
private void InitEngine () {
mRtcEngine = IRtcEngine.GetEngine (APP_ID);
// 啟用視頻
mRtcEngine.EnableVideo ();
// 允許相機回呼
mRtcEngine.EnableVideoObserver ();
// 后續與音頻相同添加回呼...
}
5. 常用 API
5.1 設定自己畫面
官方已經提供好了一個用于顯示的 VideoSurface 類,我們只要把它添加到需要顯示的物件上即可,默認顯示的即為自己相機拍攝畫面,
private void CreateMyCamera()
{
GameObject myCamera = GameObject.Find("MyCamera");
if (ReferenceEquals(myCamera, null))
{
Debug.LogError("沒有找到 MyCamera 物件!");
return;
}
else
{
// 添加顯示畫面類
myCamera.AddComponent<VideoSurface>();
// 畫面需要垂直翻轉
myCamera.transform.Rotate(0f, 0.0f, 180.0f);
}
}
5.2 設定其他用戶畫面
private void CreateUserCamera(uint uid)
{
VideoSurface videoSurface;
GameObject userCamera = GameObject.Find("UserCamera");
if (ReferenceEquals(userCamera, null))
{
Debug.LogError("沒有找到 UserCamera 物件!");
return;
}
else
{
videoSurface = userCamera.AddComponent<VideoSurface>();
userCamera.transform.Rotate(0f, 0.0f, 180.0f);
}
// 設定顯示用戶
videoSurface.SetForUser(uid);
videoSurface.SetEnable(true);
// 設定平面型別
videoSurface.SetVideoSurfaceType(AgoraVideoSurfaceType.RawImage);
// 設定畫面幀率
videoSurface.SetGameFps(30);
}
5.3 開關視頻
我們可以在應用暫停的時候,停止視頻,畫面將不會再更新,
public void EnableVideo(bool pauseVideo)
{
if (mRtcEngine != null)
{
if (!pauseVideo)
{
// 啟動視頻
mRtcEngine.EnableVideo();
}
else
{
// 關閉視頻
mRtcEngine.DisableVideo();
}
}
}
6. 最終效果
最后在 Android 上運行的效果如下:
- 我們加入到 123 頻道
- 給我們分配id 722438456,并顯示出我們自己的畫面
- 顯示頻道內另一個用戶 1173951071 的畫面
- 離開頻道,視頻畫面停止
視頻通話的 API 時序圖如下:
六、總結
總的來說,聲網的接入還是較為簡單的,我們可以從商店匯入對應的包,就能夠直接使用,最麻煩的不同平臺的配置,官方已經幫忙解決了,而且通話和視頻質量不錯,再加上有免費使用時長,對于開發者來說是相當友好的,具體細節官方檔案說的也比較清楚,
幾行就搞定了麻煩的語音和視頻,光速下班,真香,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/220852.html
標籤:其他
上一篇:散列沖突解決的方式
下一篇:Pandas概論
