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

2023-11-02

第一步、先申请一个声网账号
[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包,在另一台电脑运行,也点击加入频道。
以下是运行效果,如果另外一台也加入频道,上面会显示远端用户加入频道,
在这里插入图片描述

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

unity 使用声网(Agora)实现语音通话 的相关文章

  • Unity动画控制器animator.CrossFade

    需要特别注意 1 CrossFade虽然可以不用任何逻辑来链接而直接跳转 但是CrossFade只能覆盖其他动画 当当前动画播放完毕而没有跳出这个动画时再次调用CrossFade将会失败 造成动画依旧停在原位 参数animator Cros
  • Unity动画系统详解

    目录 动画编辑器 编辑器面板 动画复用 前言 人形重定向动画 Humanoid 通用动画 Generic 旧版本动画 Legacy 动画控制器 系统状态 切换条件 状态机脚本 IK动画 反向动力学 BlendTree 混合树 Animato
  • UnityVR--组件3--Line Renderer--线性渲染

    目录 线性渲染组件简介 绘制线条Line Renderer组件介绍 绘制拖尾Trail Renderer组件介绍 应用1 使用Line Renderer绘制线段 应用1实现 使用系统工具或自定义工具绘制线段 应用2 Trail Render
  • Unity中实现倒计时的几种方式

    1 Time time using UnityEngine public class TimeTest MonoBehaviour public float secound 10 void Update Timing private flo
  • Unity3d 插件 系列——DoTweenPro介绍(图文详细+案例)

    Unity3d 插件 系列 DoTweenPro介绍 图文详细 案例 前言 一 DoTweenPro简介 二 DoTweenPro安装 三 DoTweenPro主要组件 1 DoTweenAnimation 2 DoTweenPath 3
  • Unity中UI框架的使用1-添加面板、显示Loading页面

    其中BasePanel和Canvas都是挂在面板的预制物上的 1 导入我们的UI框架 本篇文章中有用的是两个UIPanelType NUIManager和NBasePanel 会放在文章最后供大家使用 2 先将我们做好的Panel设置成预制
  • 【IMGUI】 各种辅助类 EditorGUIUtility、EditorUtility、GUIUtility、GUILayoutUtility

    EditorGUIUtility class in Editor 继承自 GUIUtility EditorGUI 的各种辅助程序 EditorGUIUtility currentViewWidth 我尝试打印了下这个值和position
  • Unity 键盘控制人物移动——之输入方式代码的编写

    键盘输入 控制人物移动 在我们制作游戏中最常见的需求之一就是使用键盘移动游戏角色 那么我们首先需要获取键盘输入 以下提供两种方法获取键盘 这里尽量通过截图解释让大家理解代码的含义 GetInput void FixedUpdate Move
  • Unity打开工程时卡住的问题

    自从Unity升级了一个版本后 Unity打开工程卡住的问题越来越严重了 具体表现为 选择工程后 Unity窗口消失 但进程还在 有时候等个几分钟能出来 有时候等10分钟都不见得能出来 直观感受上看 似乎是Unity加载工程的时候某一步卡了
  • unity dots jobSystem 记录

    Looking for a way to get started writing safe multithreaded code Learn the principles behind our Job System and how it w
  • mixamo根动画导入UE5问题:滑铲

    最近想做一个跑酷游戏 从mixamo下载滑铲动作后 出了很多动画的问题 花了两周时间 终于是把所有的问题基本上都解决了 常见问题 1 动画序列 人物不移动 2 动画序列 人物移动朝向错误 3 蒙太奇 人物移动后会被拉回 4 蒙太奇 动画移动
  • RFID工业识别系统的优势和价值

    RFID是物联网感知层最重要的组成部分之一 它可以通过感知物品来实现智能化识别和管理 实现不同设备之间的互联 本文将深入探讨RFID工业识别系统的优势和价值 并探讨其实际应用的案例情况 RFID工业识别系统的优势和价值 RFID作为物联网感
  • 【EI会议征稿】第四届计算机网络安全与软件工程国际学术会议(CNSSE 2024)

    第四届计算机网络安全与软件工程国际学术会议 CNSSE 2024 2024 4th International Conference on Computer Network Security and Software Engineering
  • Unity学习笔记

    一 旋转欧拉角 四元数 Vector3 rotate new Vector3 0 30 0 Quaternion quaternion Quaternion identity quaternion Quaternion Euler rota
  • Unity学习笔记

    一 旋转欧拉角 四元数 Vector3 rotate new Vector3 0 30 0 Quaternion quaternion Quaternion identity quaternion Quaternion Euler rota
  • VS2022 | 显示Unreal Engine日志

    VS2022 显示Unreal Engine日志 视图 gt 其他窗口 gt Unreal Engine日志 视图 gt 其他窗口 gt Unreal Engine日志
  • U3D游戏开发中摇杆的制作(UGUI版)

    在PC端模拟摇杆 实现玩家通过控制摇杆让玩家移动 以下是完整代码 using System Collections using System Collections Generic using UnityEngine using Unity
  • U3D游戏开发中摇杆的制作(NGUI版)

    在PC端模拟摇杆 实现控制摇杆让玩家或者物体移动 以下是完整代码 using System Collections using System Collections Generic using UnityEngine public clas
  • 游戏开发创建操作之玩家信息系统的建立

    游戏一般都需要玩家信息系统 那么我们应该如何搭建玩家信息系统 接下来我将展示一种简单的方法 完整代码如下 using System Collections using System Collections Generic using Uni
  • 游戏开发常见操作梳理系列之——玩家信息的显示系统

    在游戏中 有不少游戏在左上角会出现玩家的头像和等级以及血量 这就是玩家的信息显示系统 那么这些是如何制作的呢 接下来我将讲讲代码的操作 其它操作我会在其它笔记中一一说明 敬请期待 信息的显示相当简单就是控制一些UI 然后在其它系统里面填写相

随机推荐

  • Chapter Two : Python 语言基础、运算符与表达式、程序的控制结构合集

    目录 一 Python 语言基础 1 Python 语法规则 2 关键字与标识符 3 变量 4 基本数据类型 5 输入与输出 二 运算符与表达式 1 算术运算符 2 赋值运算符 3 比较 关系 运算符 4 逻辑运算符 5 位运算符 6 赋值
  • 2023华为OD统一考试(B卷)题库清单(按算法分类),如果你时间紧迫,就按这个刷

    目录 专栏导读 华为OD机试算法题太多了 知识点繁杂 如何刷题更有效率呢 一 逻辑分析 二 数据结构 1 线性表 数组 双指针 2 map与list 3 优先队列 4 滑动窗口 5 二叉树 6 并查集 7 栈 三 算法 1 基础算法 贪心算
  • xml文件报错Unable to resolve column ‘xxx‘

    项目场景 问题描述 我在使用mybatis的逆向工程时生成的xml文件报错Unable to resolve column xxx 原因分析 需要连接到数据库 解决方案 点击右侧 填写数据库信息 点击测试 报错的话点击下放Set time
  • shell 格式化输出密码

    格式化输出 etc passwd 效果如下 root zabbix server day6 awk F BEGIN print 用户名 UID 家目录 print 1 3 6 etc passwd 用户名 UID 家目录 root 0 ro
  • Unity 移动方法总结

    Unity移动方法总结 在Unity3D中 有多重方式可以改变物体的坐标 实现移动的目的 其本质是每帧改变物体的position 通过Transform组件移动物体 Transform组件用于描述物体在空间中的状态 它包括位置 positi
  • transformers库的使用【二】tokenizer的使用,模型的保存自定义

    使用标记器 tokenizer 在之前提到过 标记器 tokenizer 是用来对文本进行预处理的一个工具 首先 标记器会把输入的文档进行分割 将一个句子分成单个的word 或者词语的一部分 或者是标点符号 这些进行分割以后的到的单个的wo
  • C——编译预处理

    编译预处理 1 宏定义 2 文件包含 3 条件编译 C语言提供的预处理 在编译之前进行 主要有三种 宏定义 文件包含和条件编译 预处理命令不是C语句 不用加分号 1 宏定义 形式 define 宏名 替换文本 define 宏名 参数 替换
  • Python元组、列表、字典、字符串常用方法超详细总结!!!

    文章目录 1 列表 list 1 1 len 1 2 max 和min 1 3 reverse 1 4 sort 1 5 clear 1 6 remove 1 7 insert 和pop 2 元组 tuple 2 1 len 2 2 cou
  • test2这篇博客的目的是test我做的小程序,请勿打开

    这篇博客的目的是test我做的小程序 请勿打开
  • SpringBoot多数据源动态切换,不影响业务逻辑正常运行,服务高可用

    SpringBoot多数据源动态切换 不影响业务逻辑正常运行 服务高可用 本文使用Spring Boot 2 4 10版本和MyBatis实现多数据源动态切换 当主库MySQL宕机后自动切换到容灾PostgreSQL数据库 数据库及数据表示
  • Altium Designer -- EMC/EMI电路设计经验

    一 基本概念 参看 电磁兼容原理及应用 讲的相当的不错 随着科学技术的不断发展 各种电气和电子设备已广泛应用于国民经济的各个部门以及人们的日常生活中 电气和电子设备在正常运行的同时 也往外发射有用或无用的电磁能量 这些能量会影响其它设备的正
  • 【React】dva-cli建立脚手架后引用css 无效

    用dva cli作为脚手架建立工程后 开始尝试编写页面 然后立马发现一个坑爹的问题 在我less文件里面写了一个class 比如 MainHead 但是编译出来之后发现css文件里面变成了 MainHead xuaz 多了一个后缀 坑爹嘛这
  • JavaScript 预解析(面试经常问)

    文章目录 预解析 预解析 解析器运行 JS 分为哪两步 预解析 执行代码 预解析 js 引擎会把 js里面所有 var 还有 function 提前到当前作用域的最前面 执行代码 从上到下执行 预解析分为 变量预解析 变量提升 和函数预解析
  • 数字图像处理第一二章

    什么是数字图像处理 数字图像处理是指借助于数 计算机来处理数字图像 当x y和灰度值f是有限的离散数值时 称该图像为数字图像 一幅图像可定义为一个二维函数f x y 其中x和y是空间 平面 坐标 而在任一对空间坐标 x y 处的幅值f称为图
  • infix 关键字

    infix适用于有单个参数的扩展函数 如果一个函数使用了infix 关键字 接收者和函数之间的点操作 以及参数的一对括号可以省略 fun String printWithDefault0 default String print this
  • 动态路由协议BGP配置实战

    1 边界网关协议BGP BGP是自治系统路由协议 用于AS间交换路由信息 通常使用在运营商 运营商之间或是企业 运营商之间 目前广为使用的是BGP 4 支持CIDR BGP协议使用TCP179端口传输 同一AS的路由之间传输的协议称为IBG
  • 在HAL库中NVIC中断配置

    中断优先级分组配置 void HAL NVIC SetPriorityGrouping uint32 t PriorityGroup 配置函数 define IS NVIC PRIORITY GROUP GROUP GROUP NVIC P
  • 关于监控方案的一点想法供参考

    Author Skate Time 2017 12 11 关于监控方案的一点想法供参考 1 监控目标 监控的直接目标 及时 准确的发现潜在事件 并辅助运维人员处理生产事件 消除生产事件专家和高手与一线员工的区别 监控的增值目标 通过高度的可
  • SW3516中文资料书

    SW3516 是一款高集成度的快充车充芯片 支持 A C 口任意口快充输出 支持双口独立限流 其集成了 5A 高效率同步降压变换器 支持 PPS PD QC AFC FCP SCP PE SFCP 低压直充等多种快充协议 CC CV 模式
  • unity 使用声网(Agora)实现语音通话

    第一步 先申请一个声网账号 Agora官网链接 https console shengwang cn 第二步在官网创建项目 选择无证书模式 证书模式需要tokenh和Appld才能通话 第三步 官网下载SDK 然后导入到unity 也可以直