unity 使用声网(Agora)实现语音通话
第一步、先申请一个声网账号
[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 updatevoid 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 framevoid 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包,在另一台电脑运行,也点击加入频道。
以下是运行效果,如果另外一台也加入频道,上面会显示远端用户加入频道,

借鉴的文章
这个文章里有视频通话,需要的小伙伴可以看这个
相关文章:
unity 使用声网(Agora)实现语音通话
第一步、先申请一个声网账号 [Agora官网链接](https://console.shengwang.cn/) 第二步在官网创建项目 ,选择无证书模式,证书模式需要tokenh和Appld才能通话 第三步 官网下载SDK 然后导入到unity,也可以直接在unity商店…...
vue2.X 中使用 echarts5.4.0实现项目进度甘特图
vue2.X 中使用 echarts5.4.0实现项目进度甘特图 效果图: 左侧都是名称,上面是时间,当中的内容是日志内容 组件: gantt.vue <template><div id"main" style"width: 100%; height: 100%"></…...
《PostgreSQL与NoSQL:合作与竞争的关系》
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🐅🐾猫头虎建议程序员必备技术栈一览表📖: 🛠️ 全栈技术 Full Stack: 📚…...
【FAQ】视频监控管理平台/视频汇聚平台EasyCVR安全检查相关问题及解决方法3.0
智能视频监控系统/视频云存储/集中存储/视频汇聚平台EasyCVR具备视频融合汇聚能力,作为安防视频监控综合管理平台,它支持多协议接入、多格式视频流分发,视频监控综合管理平台EasyCVR支持海量视频汇聚管理,可应用在多样化的场景上&…...
Java 8 新特性解读及应用实践
Java 8 新特性解读及应用实践 一、简介二、Lambda表达式三、流式编程四、日期/时间API1. 概述2. LocalDate、LocalTime、LocalDateTime等类的使用3. 格式化与解析 五、重复注解和类型注解1. 概念与作用2. 重复注解实例3. 类型注解实例 六、小结回顾 一、简介 Java 8带来了众多…...
C++项目实战——基于多设计模式下的同步异步日志系统-④-日志系统框架设计
文章目录 专栏导读模块划分日志等级模块日志消息模块日志消息格式化模块日志消息落地模块日志器模块日志器管理模块异步线程模块 模块关系图 专栏导读 🌸作者简介:花想云 ,在读本科生一枚,C/C领域新星创作者,新星计划导…...
计算机专业毕业设计项目推荐02-个人医疗系统(Java+原生Js+Mysql)
个人医疗系统(Java原生JsMysql) **介绍****系统总体开发情况-功能模块****各部分模块实现** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以也比较了解计算机专业的毕业设计流程以…...
Nginx__高级进阶篇之LNMP动态网站环境部署
动态网站和LNMP(LinuxNginxMySQLPHP)都是用于建立和运行 web 应用程序的技术。 动态网站是通过服务器端脚本语言(如 PHP、Python、Ruby等)动态生成网页内容的网站。通过这种方式,动态网站可以根据用户的不同请求生成不…...
Zebec 生态 AMA 回顾:Nautilus 以及 $ZBC 的未来
在9月7日,Zebec创始人Sam做客社区,并进行了“Nautilus Chain以及$ZBC的未来”主题的AMA访谈。Sam在本次访谈中对Nautilus Chain生态的价值捕获、Zebec生态布局规划、可能会推出的Nautilus Chain治理通证NAUT进行了解读。本文将对本次AMA进行回顾与总结。…...
NXP iMX8MM 修改 UART4至 Cortex-A53 核心
By Toradex秦海 1). 简介 NXP iMX8MM SoC UART-4 接口在默认的 ATF(ARM Trusted Firmware) 中被 RDC 分配给了 Cortex-M4 核心,用作 M4 核心的 Debug UART。如果这时候在 Cortex-A53 核心 Linux Devcie-tree 配置中使能 UART-4,就会出现 Kernel Oops 错…...
C#控制台程序中使用log4.net来输出日志
Apache log4net 库是一个帮助程序员将日志语句输出到各种输出目标的工具。log4net 是优秀的 Apache log4j™ 框架到 Microsoft .NET 运行时的端口。 我喜欢他可以自定义输出,区分等级等特点。 导入库 我们在工程里添加NuGet的包。输入名称log4net ࿰…...
用GPT干的18件事,能够真正提高学习生产力,建议收藏
用GPT干的18件事,能够真正提高学习生产力,建议收藏。 语法更正 文本翻译 语言转换 代码解释 修复代码错误 作为百科全书 信息提取 好友聊天 创意生成器 采访问题 论文大纲 故事创作 问题类比 创建 SQL 需求 情感分析 将产品描述转变为广告 关键字提取 闲…...
线性代数的本质(二)——线性变换与矩阵
文章目录 线性变换与矩阵线性变换与二阶方阵常见的线性变换复合变换与矩阵乘法矩阵的定义列空间与基矩阵的秩逆变换与逆矩阵 线性变换与矩阵 线性变换与二阶方阵 本节从二维平面出发学习线性代数。通常选用平面坐标系 O x y Oxy Oxy ,基向量为 i , j \mathbf i,…...
JavaScript获取字符串的字节长度
概要 提示:大家都知道,获取字符串的长度可用length来获取。 那么获取这段字符串的字节数呢?英文字母肯定lenght和字节数都一样:都是1而中文lenght1,字节数2因此,需要作的就是把中文字符的字节数计算出来。 …...
[2023.09.13]: Rust Lang,避不开的所有权问题
Rust的所有权问题,在我学Rust的时候就跳过了,因为我知道这玩意儿没有场景就不好理解。没想到场景很快就出现了。 在开发Yew应用组件的时候,涉及到了事件,闭包,自然就引出了所有权问题。 话不多说,下面让我们…...
Redux中间件源码解析与实现
基本介绍 本文中涉及到的关键npm包的版本信息如下: react 的版本为18.2.0 redux的版本为4.1.2 redux-thunk版本为2.4.2 redux-promise版本为0.6.0 redux-logger版本为3.0.6 在Redux源码解析与实现(一)Redux源码解析与实现(二&…...
关于rsync用不了之后
1.尝试找出rsync使用错误原因: 我遇见一个问题:rsync:read errors mapping:communication error on send (70),我查了一下这个问题很大可能是网络链接导致的,然后我用nslookup指令查看了/train2…...
由一个多线程并发保存而引发的思考
1. 问题描述 问题描述,现A表(用户查看实验的次数)有user_id和exp_id两个字段,其中user_id加exp_id不唯一。B表有user_id,exp_id以及exp_num三个字段,其中user_id加exp_id唯一(表中未建唯一索引)。 现需要将A表的数据同步到B表,单机模式通过定时任务同步。A表的数据有…...
python-vlc
文章目录 关于 python-vlc安装使用关于 python-vlc Python vlc bindings github : https://github.com/oaubert/python-vlcPython bindings (ctypes-based) for VLC http://olivieraubert.net/vlc/python-ctypes/关于 VLC 可参考 macOS - 安装使用 VLC https://blog.csdn.net/…...
2023长城杯 web部分题目(seekingeasy_extension)
seeking 下载题目附件得到: <?php error_reporting(0); header("HINT:POST n range(1,10)");$image $_GET[image]; echo "这里什么也没有,或许吧。"; $allow range(1, 10); shuffle($allow); if (($_POST[n] $allow[0])) …...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
ABB馈线保护 REJ601 BD446NN1XG
配电网基本量程数字继电器 REJ601是一种专用馈线保护继电器,用于保护一次和二次配电网络中的公用事业和工业电力系统。该继电器在一个单元中提供了保护和监控功能的优化组合,具有同类产品中最佳的性能和可用性。 REJ601是一种专用馈线保护继电器…...
【仿生机器人】刀剑神域——爱丽丝苏醒计划,需求文档
仿生机器人"爱丽丝"系统架构设计需求文档 一、硬件基础 已完成头部和颈部硬件搭建 25个舵机驱动表情系统 颈部旋转功能 眼部摄像头(视觉输入) 麦克风阵列(听觉输入) 颈部发声装置(语音输出)…...
论文笔记:Large Language Models for Next Point-of-Interest Recommendation
SIGIR 2024 1 intro 传统的基于数值的POI推荐方法在处理上下文信息时存在两个主要限制 需要将异构的LBSN数据转换为数字,这可能导致上下文信息的固有含义丢失仅依赖于统计和人为设计来理解上下文信息,缺乏对上下文信息提供的语义概念的理解 ——>使用…...
