记录:利用 Agora 在 Unity3D MRTK场景中创建实时视频聊天应用

目录

    • 准备
    • [1. 安装Agora_Unity_RTC_SDK](#1. 安装Agora_Unity_RTC_SDK)
    • [2. 创建UI](#2. 创建UI)
    • [3. script具体内容](#3. script具体内容)
    • [4. 使用测试](#4. 使用测试)
  • 本质是两部带摄像机的设备同时进入Agora聊天室内视频。

  • 去年实现过一次这个功能,用的是Agora_Unity_RTC_SDK 4.2.2版本的,今年使用失败,遂重新安装最新版本Agora_Unity_RTC_SDK(4.3.2)并按照官方教程配置,但发现不能正常使用。解决之后,特此记录。

  • 本文假设已经有了Unity3D Scene并安装好了MRTK。

准备

名称 版本
设备A 使用其浏览器
设备B 安装了Unity
Unity 2202.3.9.f1
MRTK 2.8.3.0
Agora_Unity_RTC_SDK 4.3.2

建议使用两台设备测试来避免出现相机占用的问题。

1. 安装Agora_Unity_RTC_SDK

SDK下载链接:https://docs.agora.io/en/sdks?platform=unity,点击import就可以导入project中。

2. 创建UI

英文版官方说明:https://docs.agora.io/en/video-calling/get-started/get-started-sdk?platform=unity

我们需要(名字都不可以改动,会影响SDK的使用):

名称 属性
TestCanvas Canvas
LocalView Raw Image
Join Button
Leave Button
RemoteView Cube 我设的size:(1,1,0.01)

其中,RemoteView会放入MixedRealitySceneContent中以实现可以在AR场景中看见RemoteView中的内容;其他都放在创建的TestCanvas中。

3. script具体内容

我创建了JoinChannelView.cs并将其挂在上一步创建的TestCanvas上。以下是JoinChannelView.cs的具体内容:

csharp 复制代码
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Serialization;
using Agora.Rtc;

#if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID)
using UnityEngine.Android;
#endif

public class JoinChannelVideo : MonoBehaviour
{
    // Fill in your app ID
    private string _appID = "待填";
    // Fill in your channel name
    private string _channelName = "待填";
    // Fill in a temporary token
    private string _token = "待填";

    internal VideoSurface LocalView;
    internal VideoSurface RemoteView;
    internal IRtcEngine RtcEngine;
        
        
    #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID)
    private ArrayList permissionList = new ArrayList() { Permission.Camera, Permission.Microphone };
    #endif

    // Start is called before the first frame update
    void Start()
    {
        SetupVideoSDKEngine();
        InitEventHandler(); 
        SetupUI();
    }

    private void InitEventHandler()
    {
        UserEventHandler handler = new UserEventHandler(this);
        RtcEngine.InitEventHandler(handler);
    }

    private void SetupUI()
    {
        GameObject go  = GameObject.Find("RemoteView");
        RemoteView = go.AddComponent<VideoSurface>();
        go.transform.Rotate(0.0f, 0.0f, -180.0f);

        go = GameObject.Find("LocalView");
        LocalView = go.AddComponent<VideoSurface>();
        go.transform.Rotate(0.0f, 0.0f, -180.0f);

        go = GameObject.Find("Leave");
        go.GetComponent<Button>().onClick.AddListener(Leave);
        go = GameObject.Find("Join");
        go.GetComponent<Button>().onClick.AddListener(Join);

        //Join();
    }

    public void Join(){
        // Enable the video module
        RtcEngine.EnableVideo();
        // Set channel media options
        ChannelMediaOptions options = new ChannelMediaOptions();
        // Start video rendering
        LocalView.SetEnable(true);
        // Automatically subscribe to all audio streams
        options.autoSubscribeAudio.SetValue(true);
        // Automatically subscribe to all video streams
        options.autoSubscribeVideo.SetValue(true);
        // Set the channel profile to live broadcast
        options.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_COMMUNICATION);
        //Set the user role as host
        options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
        // Join a channel
        RtcEngine.JoinChannel(_token, _channelName, 0, options);
    }
    public void Leave() 
    {
        Debug.Log("Leaving _channelName");
        // Leave the channel
        RtcEngine.LeaveChannel();
        // Disable the video module
        RtcEngine.DisableVideo();
        // Stop remote video rendering
        RemoteView.SetEnable(false);
        // Stop local video rendering
        LocalView.SetEnable(false);
    }

    // Update is called once per frame
    void Update() {
        CheckPermissions();
    }


    private void CheckPermissions() {
        #if (UNITY_2018_3_OR_NEWER && UNITY_ANDROID)
        foreach (string permission in permissionList) {
            if (!Permission.HasUserAuthorizedPermission(permission)) {
                Permission.RequestUserPermission(permission);
            }
        }
        #endif
    }

    private void SetupVideoSDKEngine()
    {
            // Create an IRtcEngine instance
            RtcEngine = Agora.Rtc.RtcEngine.CreateAgoraRtcEngine();
            RtcEngineContext context = new RtcEngineContext();
            context.appId = _appID;
            context.context = 0;
            context.channelProfile = CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING;
            context.audioScenario = AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT;
            // Initialize the instance
            RtcEngine.Initialize(context);
    }

}

// Implement your own EventHandler class by inheriting the IRtcEngineEventHandler interface class implementation
internal class UserEventHandler : IRtcEngineEventHandler
{
    private readonly JoinChannelVideo _videoSample;
    internal UserEventHandler(JoinChannelVideo videoSample)
    {
        _videoSample = videoSample;
    }
    // error callback
    public override void OnError(int err, string msg)
    {
    }
    // Triggered when a local user successfully joins the channel
    public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)
    {
        _videoSample.LocalView.SetForUser(0, "");
    }
    // When the SDK receives the first frame of a remote video stream and successfully decodes it, the OnUserJoined callback is triggered.
    public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed)
    {
        // Set the remote video display
        _videoSample.RemoteView.SetForUser(uid, connection.channelId, VIDEO_SOURCE_TYPE.VIDEO_SOURCE_REMOTE);
        // Start video rendering
        _videoSample.RemoteView.SetEnable(true);
        Debug.Log("Remote user joined");
    }
}

这里需要注意 的是函数SetupVideoSDKEngine,官方的写法是:

csharp 复制代码
private void SetupVideoSDKEngine()
{
    // Create an IRtcEngine instance
    RtcEngine = Agora.Rtc.RtcEngine.CreateAgoraRtcEngine();
    RtcEngineContext context = new RtcEngineContext(_appID, 0,CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING, AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT);
    // Initialize the instance
    RtcEngine.Initialize(context);
}

感觉和我的修改的代码没有什么本质区别,但我测试过,用官方的教程无法获得RemoteView内容。

此外,internal class UserEventHandler : IRtcEngineEventHandler {}函数需要放在public class JoinChannelVideo : MonoBehaviour {}外面,之前由于对c#不熟悉将internal class UserEventHandler放在public class JoinChannelVideo里,虽然不会报错,但也不能正常使用。

4. 使用测试

注册Agora,并创建Project,注册连接:https://console.agora.io/v2


  1. 把名为 My New Project 的 project 的 APP IDChannel NameToken 填入设备A 打开的浏览器:Agora Basic Video Call 中连接:https://webdemo.agora.io/basicVideoCall/index.html#,点击 Join
  2. 设备B 的Unity Project中,修改JoinChannelVideo内容:
csharp 复制代码
public class JoinChannelVideo : MonoBehaviour
{
    // Fill in your app ID
    private string _appID = "e6fd32eba33741e68641f504580e7d29";
    // Fill in your channel name
    private string _channelName = "My New Project";
    // Fill in a temporary token
    private string _token = "007eJxTYHB7f9nyxhpbtncH1e8YsNm8qVX09fs7o6pqjvZ7A+u5wXoKDKlmaSnGRqlJicbG5iaGqWYWZiaGaaYGJqYWBqnmKUaW3zfkpjUEMjJwXz3LysgAgSA+H4NvpYJfarlCQFF+VmpyCQMDAIqPIqw=";

    internal VideoSurface LocalView;
    internal VideoSurface RemoteView;
    internal IRtcEngine RtcEngine;

点击按键 JoinLeave 控制视频开启和离开。

结果展示,在AR场景内只看见RemoteView的内容:

|-------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
| 网页 | Unity |
| | |

相关推荐
zh路西法11 分钟前
【C++决策和状态管理】从状态模式,有限状态机,行为树到决策树(二):从FSM开始的2D游戏角色操控底层源码编写
c++·游戏·unity·设计模式·状态模式
橘子遇见BUG4 小时前
Unity Shader学习日记 part 3 线性代数--矩阵变换
学习·线性代数·unity·矩阵·图形渲染
Artistation Game7 小时前
一、c#基础
游戏·unity·c#·游戏引擎
成都渲染101云渲染66668 小时前
云渲染,Enscape、D5、Lumion渲染提速教程
运维·服务器·unity·电脑·图形渲染·blender·houdini
超龄魔法少女1 天前
[Unity] ShaderGraph动态修改Keyword Enum,实现不同效果一键切换
unity·技术美术·shadergraph
蔗理苦1 天前
2024-12-24 NO1. XR Interaction ToolKit 环境配置
unity·quest3·xr toolkit
花生糖@1 天前
Android XR 应用程序开发 | 从 Unity 6 开发准备到应用程序构建的步骤
android·unity·xr·android xr
向宇it1 天前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
向宇it2 天前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
向宇it2 天前
【从零开始入门unity游戏开发之——C#篇26】C#面向对象动态多态——接口(Interface)、接口里氏替换原则、密封方法(`sealed` )
java·开发语言·unity·c#·游戏引擎·里氏替换原则