unity 使用声网(Agora)实现语音通话

news2024/12/23 19:49:22

第一步、先申请一个声网账号
[Agora官网链接](https://console.shengwang.cn/)
第二步在官网创建项目 ,选择无证书模式,证书模式需要tokenh和Appld才能通话
在这里插入图片描述
第三步 官网下载SDK 然后导入到unity,也可以直接在unity商店里下载,Agora官网下载链接
在这里插入图片描述
第四步 运行官方Demo
1、导入后会有这些文件
在这里插入图片描述
2、从官网新建的项目复制AppID,粘贴到这个位置,如果使用的是证书模式,Token也需要填写,否者运行报错110,第三个变量是频道,可以自定义, ,Examples里的场景都是Demo,
在这里插入图片描述
3、找到这个场景,这个是语音通话的Demo场景
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
按照以上步骤,这是运行,就可以实现语音通话了,
如果运行有显示110等错误码,可以查看官网的解决方法,
错误码处理链接

声网每个月有一万分钟免费时长,非常赞
也可以按照官方文档去实现语音通话,文档写的非常清楚,代码都有,我按照吧官方文档的代码粘贴到一个脚本里,运行完全没问题,
上脚本(外加了一些回调事件的补充),

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Agora.Rtc;
using UnityEngine.UI;
using UnityEngine.Serialization;
using Agora_RTC_Plugin.API_Example;
using Logger = Agora_RTC_Plugin.API_Example.Logger;

public class Test : MonoBehaviour
{
    [FormerlySerializedAs("appIdInput")]
    [SerializeField]
    private AppIdInput _appIdInput;
    // 填入你的 app ID。
    private string _appID = "";
    // 填入你的频道名。
    private string _channelName = "";
    // 填入 Token。
    private string _token = "";
    internal IRtcEngine RtcEngine;
    public Text conten;

    internal Logger Log;
    // Start is called before the first frame update
    void Start()
    {
        LoadAssetData();
        if(CheckAppId() )
        {
            SetupVideoSDKEngine();
            InitEventHandler();
            SetupUI();
        }
       
    }
    private void LoadAssetData()
    {
        if (_appIdInput == null) return;
        _appID = _appIdInput.appID;
        _token = _appIdInput.token;
        _channelName = _appIdInput.channelName;
    }

    private bool CheckAppId()
    {
        Log = new Logger(conten);
        return Log.DebugAssert(_appID.Length > 10, "Please fill in your appId in API-Example/profile/appIdInput.asset!!!!!");
    }
    // Update is called once per frame
    void Update()
    {
        CheckPermissions();
    }
    void OnApplicationQuit()
    {
        if (RtcEngine != null)
        {
            Leave();
            // 销毁 IRtcEngine。
            RtcEngine.Dispose();
            RtcEngine = null;
        }
    }
    private void SetupVideoSDKEngine()
    {
        // 创建 IRtcEngine 实例。
        RtcEngine = Agora.Rtc.RtcEngine.CreateAgoraRtcEngine();
        RtcEngineContext context = new RtcEngineContext(_appID, 0, CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING, AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT);
        // 初始化 IRtcEngine。
        RtcEngine.Initialize(context);

    }
    // 创建用户回调类实例,并设置回调。
    private void InitEventHandler()
    {
        UserEventHandler handler = new UserEventHandler(this);
        RtcEngine.InitEventHandler(handler);
    }

    private void SetupUI()
    {
        GameObject go = GameObject.Find("Leave");
        go.GetComponent<Button>().onClick.AddListener(Leave);
        go = GameObject.Find("Join");
        go.GetComponent<Button>().onClick.AddListener(Join);
    }
    public void Join()
    {
        Debug.Log("Joining _channelName");
        // 启用音频模块。
        RtcEngine.EnableAudio();
        // 设置频道媒体选项。     
        ChannelMediaOptions options = new ChannelMediaOptions();
        // 自动订阅所有音频流。
        options.autoSubscribeAudio.SetValue(true);
        // 将频道场景设为直播。
        options.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING);
        // 将用户角色设为主播。
        options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
        // 加入频道
        // channelKey: 动态秘钥,无证书模式(非安全模式)传入 null;安全模式需要传入服务器生成的 Token
        // channelName: 频道名称
        // info: 开发者附带信息(非必要),不会传递给频道内其他用户
        // uid: 用户ID,0 为自动分配
        RtcEngine.JoinChannel(_token, _channelName, 0, options);
    }
    public void Leave()
    {
       
        Debug.Log("Leaving _channelName");
        // 离开频道。
        RtcEngine.LeaveChannel();
        // 关闭音频模块。
        RtcEngine.DisableAudio();
    }

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

// 实现你自己的回调类,可以继承 IRtcEngineEventHandler 接口类实现。
internal class UserEventHandler : IRtcEngineEventHandler
{
    private readonly Test _audioSample;

    internal UserEventHandler(Test audioSample)
    {
        _audioSample = audioSample;
    }

    // 发生错误回调。
    public override void OnError(int err, string msg)
    {
    }
    // 当前通话统计回调,每两秒触发一次。
    public override void OnRtcStats(RtcConnection connection, RtcStats stats)
    {
       
    }
    // Token 过期回调
    public override void OnRequestToken(RtcConnection connection)
    {
        
    }
    // Token 即将过期提醒
    public override void OnTokenPrivilegeWillExpire(RtcConnection connection, string token)
    {
        base.OnTokenPrivilegeWillExpire(connection, token);
    }
    /// <summary>
    /// 网络发生变化时的回调
    /// </summary>
    /// <param name="connection"></param>
    /// <param name="state">当前连接的状态</param>
    /// <param name="reason">连接状态改变的原因</param>
    public override void OnConnectionStateChanged(RtcConnection connection, CONNECTION_STATE_TYPE state, CONNECTION_CHANGED_REASON_TYPE reason)
    {
     
    }
   
    // 网络中断回调(建立成功后才会触发)
    public override void OnConnectionInterrupted(RtcConnection connection)
    {
       
    }
    // 网络连接丢失回调
    public override void OnConnectionLost(RtcConnection connection)
    {
        base.OnConnectionLost(connection);
    }
   
    //重新链接网络后加入频道
    public override void OnRejoinChannelSuccess(RtcConnection connection, int elapsed)
    {
     
    }
    // 本地用户成功加入频道时,会触发该回调。
    // channelId:频道名称
    // uid:用户ID(发起请求时候如果没有指定,服务器会自动分配一个)
    // elapsed:从本地用户调用 JoinChannelByKey 到该回调触发的延迟(毫秒)。
    public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)
    {
        string joinChannelMessage = string.Format("用户ID:{0},加入频道:{1}", connection.localUid, connection.channelId);
        _audioSample.Log.UpdateLog(joinChannelMessage);
    }
    // 本地用户离开频道的回调
    // stats:通话统计的数据
    //      duration:通话时长
    //      txBytes:发送字节数(bytes)
    //      rxBytes:接收字节数(bytes)
    //      txKBitRate:发送码率(kbps)
    //      rxKBitRate:接收码率(kbps)
    public override void OnLeaveChannel(RtcConnection connection, RtcStats stats)
    {
        string leaveMessage = string.Format("用户ID:{0},离开频道:{1},通话时长:{2}秒", connection.localUid, connection.channelId, stats.duration);
        _audioSample.Log.UpdateLog(leaveMessage);
    }
    // 远端用户成功加入频道时,会触发该回调。
    public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed)
    {
        string userJoinedMessage = string.Format("远端用户ID:{0},加入频道:{1}", uid, connection.channelId);
        _audioSample.Log.UpdateLog(userJoinedMessage);
    }
    // 远端用户离开当前频道时会触发该回调。
    // reason:离线原因(主动离开、超时、直播模式身份切换)
    public override void OnUserOffline(RtcConnection connection, uint uid, USER_OFFLINE_REASON_TYPE reason)
    {
        string userOfflineMessage = string.Format("远端用户ID:{0},离开频道:{1}", uid, connection.channelId);
        _audioSample.Log.UpdateLog(userOfflineMessage);
    }
    // 提示频道内谁在说话
    // speakers:说话人信息
    // speakerNumber:说话人数[0,3]
    // totalVolume:总音量
    public override void OnAudioVolumeIndication(RtcConnection connection, AudioVolumeInfo[] speakers, uint speakerNumber, int totalVolume)
    {
        base.OnAudioVolumeIndication(connection, speakers, speakerNumber, totalVolume);
    }
    // 用户静音提示回调
    // uid:用户 ID
    // muted:是否静音
    public override void OnUserMuteAudio(RtcConnection connection, uint remoteUid, bool muted)
    {
        base.OnUserMuteAudio(connection, remoteUid, muted);
    }
  
}

脚本使用方法,新建一个场景,以及搭两个按钮,和一个滑动框,把脚本随便挂载一个物体身上即可,
在这里插入图片描述
ContentSizeFitter可以让UI随文字自适应
在这里插入图片描述
然后运行,点击加入频道,打包PC包,在另一台电脑运行,也点击加入频道。
以下是运行效果,如果另外一台也加入频道,上面会显示远端用户加入频道,
在这里插入图片描述

借鉴的文章
这个文章里有视频通话,需要的小伙伴可以看这个

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1006651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云链商城连锁门店新零售O20系统以零售商城

云链商城连锁门店新零售O20系统以零售商城、门店收银、多渠道进销存、客户管理、互动营销、导购助手、多种奖励模式和数据分析等功能&#xff0c;赋能多品牌连锁门店实现线上线下商品、会员、场景的互联互通&#xff0c;助推企业快速实现营销、服务、效率转型升级&#xff0c;为…

可编程交易区块为DeFi机器人提供强大动力

对于选择基金投资的人来说&#xff0c;一个基本指导原则就是寻找那些管理费最低的基金。资本应该是在运转&#xff0c;而不是用于支付费用。同样&#xff0c;Mysten Lab的Capy交易机器人利用可编程交易区块&#xff08;Programmable Transaction Blocks &#xff0c;PTBs&#…

文章生成器在线使用-自动生成文章的工具

大家好啊&#xff0c;今天我要和大家聊聊一个非常热门的话题——在线文章生成器。主要是帮助我们解决写作困扰&#xff0c;节省大量的时间和精力。我也常遇到常为了写一篇好文章而愁眉苦脸呢&#xff0c;我测试过可以帮助我们生成优质的文章&#xff0c;确实让我们的写作变得简…

1. 微信公众号申请加认证

文章目录 微信公众号申请流程指引微信公众号申请流程注册微信公众号申请完成银行卡账号验证 如何查询微信公众号审核通过登录微信公众号平台后&#xff08;如下图&#xff09;致电微信客服热线 微信公众号认证流程指引微信公众号认证流程选择 微信认证/开通选择验证方式。填写微…

运动耳机哪种类型好、最佳运动耳机推荐

很多人都有着运动的习惯&#xff0c;不论是为了解压放松还是为了健身减肥。而运动方式也是多种多样&#xff0c;包括骑行、跑步、游泳等。 作为“运动伴侣”的运动耳机&#xff0c;很多人都不知道该选择哪一款。通常都是建议大家再运动过程中佩戴专业的运动耳机&#xff0c;因为…

【图像处理】怎么让图片背景变透明?怎么改变图片中线条的颜色?在线PS软件

文章目录 前言一、打开图二、背景透明处理三、改变线条颜色总结 前言 我们处理图片将会使用到PS软件&#xff0c;如果安装了PS那直接打开使用。 如果没有安装PS&#xff0c;可使用在线PS软件&#xff1a; https://www.uupoop.com/#/ 一、打开图 第一步&#xff0c;从这个入口…

线性矩阵不等式(LMI)在控制理论中的应用

目录 &#xff08;一&#xff09;Matlab中的LMI处理工具包 &#xff08;二&#xff09;为什么LMI成为控制理论领域重要工具&#xff1f; &#xff08;三&#xff09;LMI在与Lyapunov不等式的关系 &#xff08;1&#xff09;线性矩阵不等式 &#xff08;2&#xff09;线性矩阵…

如何进行有效测试?——基于MEAP诞生的软件测试实用指南告诉你

近年来出现了一 些新的出版方式&#xff0c;MEAP(Manning Early Access Program)就是其中的一种&#xff0c;把开源运动扩展到出版行业。在MEAP中&#xff0c;读者可在图书出版前逐章阅读早期版本。在作者写作过程中&#xff0c;读者可以及时提供反馈&#xff0c;帮助作者写出更…

苹果发布会,华为成热搜第一?

文 | 琥珀消研社 作者 | April叶 琥珀消研社快评&#xff1a;雷蒙多给华为手机“代言”后&#xff0c;苹果库克又给华为“代言”了&#xff0c;苹果发布会当晚&#xff0c;华为竟然登顶热搜第一#苹果发布会 #华为 #Mate 60 Pro#手机#科技 苹果开发布会&#xff0c;华为却冲上…

Matplotlib | 高阶绘图案例【3】- 五大战区高校排名

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. 数据处理2.1 高效数据2.2 学校排名 &#x1f3f3;️‍&#x1f308; 3. 绘图3.1 绘制图布&#xff0c;设置极坐标系3.2 绘制学校排名柱状图3.3 绘制五大战区扇形区域3.4 添加战区、学校…

javaSE___语法基础(关键字、标识符、数据类型、字符、字符串、运算符)

语法基础 一、关键字的概述和使用二、标识符的概述和组成规则三、标识符中常见的命名规则四、数据类型的概述和分类五、数据类型的概述和分类六、数据类型转换之强制转换七、数据类型转换之强制转换超出范围八、字符和字符串参与运算九、算术运算符的基本用法十、算术运算符和-…

闭包的理解

1.什么是闭包&#xff1f; 变量的私有化。一个函数内的变量,随着函数的执行完毕,对于的变量也会随着销毁,闭包可以让变量在函数执行完毕之后不必销毁,通常将这个变量通过匿名函数的形式return出去,这个变量只能被访问,不能被修改。 2.证明变量执行玩被销毁 (1)函数体没有被包…

((type *)0)->member的用法

问题缘由&#xff0c;在学习 rt-thread 内核的时候遇到了这么一行代码&#xff1a; to_thread rt_list_entry(rt_thread_priority_table[0].next,struct rt_thread, tlist); 而 rt_list_entry 的宏定义如下&#xff1a; /* 已知一个结构体里面的成员的地址&#xff0c;反推…

利用 Python 中的地理空间数据与 GeoPandas

推荐&#xff1a;使用 NSDT编辑器快速搭建3D应用场景 空间数据的真正潜力在于它能够连接数据点及其各自的位置&#xff0c;为高级分析创造无限的可能性。地理空间数据科学是数据科学中的一个新兴领域&#xff0c;旨在利用地理空间信息并通过空间算法和机器学习或深度学习等先进…

Android:使用命令行发现keytool不是内部命令解决办法

一、前言&#xff1a;最近在搞引入高德地图的SDK&#xff0c;发现需要给app签名打包。记录一下。 二、当我在命令行中输入keytool的时候说keytool不是内部命令 解决方案&#xff1a; 找到系统属性--------高级----------点击环境变量 双击点开 找到java\jre1.8.0_202\bin新建…

GLTF在线编辑器

GLTF在线编辑器提供了一个内置的模型查看器&#xff0c;可以加载和预览 glTF/glb 文件。用户可以在不用安装任何插件的情况下直接在浏览中快速查看和编辑器3D模型。 它的功能特点如下&#xff1a; 1、打开GLTF模型 用户可以在GLTF编辑器中拖入GLB/GLTF模型或者选择打开本地GL…

Bootstarp4 设计网页轮播组件

很多网站都有广告轮播功能&#xff0c;可使用bootstrap4中的carousel组件非常简单的实现。 目录 下载bootstrap4 轮播功能实现 简单实现轮播组件 增加标识图标 增加标题和说明 切换淡入淡出 设置数据间隔 总结 下载bootstrap4 下载 Bootstrap Bootstrap v4 中文文档 …

Android13 下拉菜单栏中添加快捷截图按钮

Android 13 原生系统下拉状态栏中是没有快捷截图按钮,现在需要添加快捷截图功能。 添加快捷截图功能后的效果图: 涉及修改的文件如下: modified: vendor/mediatek/proprietary/packages/apps/SystemUI/res/values/config.xml modified: vendor/mediatek/proprietary/…

软件测试的流程有哪些?

一、需求调研 1. 委托方提供资料 A. 填写测试委托申请表 B. 操作手册 C. 开发需求规格说明书 D. 开发合同及招标文件等 2. 双方技术沟通确定测试具体内容&#xff0c;如功能性测试、性能效率测试、信息安全性测试、兼容性测试、可靠性测试等。 3. 我方给出测试方案及报价…

SpringMVC学习|Servlet回顾、理解SpringMVC小demo、SpringMVC原理

Servlet回顾 创一个空的maven父工程&#xff0c;导入相关依赖&#xff0c;测试的、spring的、servlet的、jsp以及jstl标签的。 创建一个空的maven子项目&#xff0c;并添加web支持 为了保险起见&#xff0c;在子项目中添加servlet和jsp的依赖 编写一个Servlet类&#xff0c;实…