Unity 語音和視頻通話快速解決方案——聲網 SDK接入指南(Android)

Unity 語音和視頻通話快速解決方案——聲網 SDK接入指南(Android)

1、前言

當前遊戲爲了增長社交互動和代入感,好比狼人殺、團隊競技遊戲等,常常會產生須要實時語音和視頻通話的需求。可是對於我的開發者和小團隊,這種須要先後端配合,重網絡的開發需求會帶來很大的挑戰。android

爲此咱們須要尋找一個成熟、可靠的解決方案。每月提供 10000 分鐘無償使用時長聲網 Agora成爲了個人最佳選擇。而且聲網的 SDK(Software Development Kit) 包體積很小,運行時CPU和內存佔用率低,對於移動端的遊戲開發很友好。2019年7月聲網正式成爲了 Unity 官方認證合做夥伴,語音和視頻的 SDK 也已經發布在了 Unity 資源商店中,可以很是方便的接入。c#

注意:語音和視頻的包有衝突,不兼容(一些庫和平臺配置不一樣,能夠本身手動修改),請根據需求,第四步和第五步二選一。引擎支持開關視頻和聲音,因此能夠接入視頻 SDK 包,關閉視頻,僅僅使用語音通話。後端

2、後臺建立應用

爲了方便後續接入操做,這裏先註冊和登陸到 官方後臺 建立應用,獲取咱們以後須要的 App ID。能夠根據官網的新手引導來建立應用,也能夠參考以下步驟。api

輸入項目名稱,目前暫時使用 APP ID 的鑑權模式,後續根據須要也能夠在項目編輯界面切換到 Token 鑑權模式,該模式更加安全,生成 Token 程序須要搭建在服務器上,能夠參考官方文檔安全

建立成功後,咱們點擊 APP ID 下的顯示按鈕,APPID 就會複製到粘貼板。服務器

3、獲取 SDK

這裏我使用的 Unity 版本爲 2019.3.14,進入商店咱們搜索 Agora,能夠發現視頻和語音兩個 SDK 包。網絡

若是打不開 Unity Store 的同窗還能夠從官網開發者中心下載。app

4、接入 Agora Voice 語音 SDK

1. 導入工程

從 Asset Store 的個人資源(My Asset)中找到咱們下載的 Agora Voice SDK For Unity ,點擊 Import 導入到工程中。編輯器


導入的文件結構以下。ide

  • 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 上的效果以下:

  1. 輸入1234 成功加入頻道,分配給咱們用戶 id:1186284123
  2. 有其餘用戶加入,用戶id:2996662973
  3. 用戶id:2996662973 開啓靜音
  4. 用戶id:2996662973 離開頻道
  5. 咱們離開頻道,顯示通話統計數據

語音通話的 API 時序圖以下:

5、接入 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 上運行的效果以下:

  1. 咱們加入到 123 頻道
  2. 給咱們分配id 722438456,並顯示出咱們本身的畫面
  3. 顯示頻道內另外一個用戶 1173951071 的畫面
  4. 離開頻道,視頻畫面中止

視頻通話的 API 時序圖以下:

6、總結

總的來講,聲網的接入仍是較爲簡單的。咱們能夠從商店導入對應的包,就可以直接使用,最麻煩的不一樣平臺的配置,官方已經幫忙解決了。並且通話和視頻質量不錯,再加上有無償使用時長,對於開發者來講是至關友好的。具體細節官方文檔說的也比較清楚。

幾行就搞定了麻煩的語音和視頻,光速下班,真香。

相關文章
相關標籤/搜索