基于声网 Agora 信令 SDK 开发聊天室应用(一)
文章作者:monkeyHi
本文是 声网 Agora 开发者的投稿。如有疑问,欢迎与作者交流。
社会高度发展的今天,大家都离不开社交和社交网络。近几年,直播行业的稳定高速发展,背后隐藏一个事实,大家需要一个实时性更高的互联网环境,就像面对面沟通那样的及时有效。
这次尝试了一下 Agora SignalingSDK。
初识 Agora 信令 SDK
Agora Signaling 是Agora 全家桶一员,主要用来实现即时点对点通信。Agora Signalling 是作为插件的形式服务于 Agora 全家桶,也可以单独用于实时消息通信的场景。
开发文档
Agora 官网已经提供了比较完善的文档资料。
以 Agroa Signaling 为例,我们可以看到官网分别就客户端集成和服务端集成进行了介绍,而客户端部分又针对常见客户端实现进行的清晰简单的讲解。
拥有一定开发经验的攻城狮很快便能上手。
当然我们也发现一个问题,文档上只有 quick start, 没有进一步介绍接口使用的注意事项。带着这个疑惑,笔者迅速浏览了API参考部分,所有接口都没有提供具体的demo code 和注意事项。基本接入思路是这样的:
初始化
登录
点对点消息
频道消息
呼叫邀请
注销
官方 Demo
Agroa 官网提供了关于 Agora 信令的各种demo,初略浏览一番,比较容易看懂,没有什么很奇怪的写法。
但是,这些demo都有一个问题,没有注释。这对不曾接触Agora产品的新手不是特别友好,可能要花比较多精力来熟悉这些接口。
可能的一些应用场景
通过Agora 官网及已经公布的API 。我们可以了解到,常见带身份信息的文本聊天完全不在话下,基于Agora Signaling的demo,我们只要关心一下自己的业务模型,端上套个皮就能实现聊天室、留言板等互动交流场景。
直播间的弹幕聊天
直播间聊天和弹幕聊天,本质上就是一个留言板和即时通讯的合体。而Agora 信令 本身就是为实时通信互动而生,实现这样的功能只要加一个聊天数据库来保留历史记录即可。
医患远程诊断
现实生活中,受距离、时间、心理等诸多因素影响,病患并不一定能及时到达医院,医生也未必能及时到达现场,这时候及时通讯网络可以提供诸多方便。病患或病患家属可以通过一个App 将患情通过影像、声音、文字传递给医生,同时可以随时的沟通,就像现场问诊一样,病患可能也需要一个病友群或频道来分享交流。
消息通知
相信大家对手机短信、微信消息、qq消息都不陌生,我们借助 Agora 信令 也是可以实现简单版本的网络短信功能的。
客服功能
有些产品可能需要一个客服功能,这样遇到使用问题时,可以随时通过聊天窗口咨询,而且不需要额外的添加客服人员的微信。有效沟通,同时保护彼此隐私。
实时性比较高的设备间通信
比如我在A省有一批矿机,需要及时的了解机房状况,那么我在机房可以设置一个通信机,将采集到的数据通过 Agora 信令 及时传回并记录在数据库。虽然这个场景可能并不是Agora 信令 设计初衷,但作为一种可行的备选也是不错的。
课堂在线互动
各种在线学堂的远程授课方案,包括远程考试等,课堂互动可不局限于文字、语音、图像,通常要结合起来。
直播导购互动
如果有这样一种直播活动,画面上和电视导购没什么区别,但是可以通过更方便的方式下单,扫码,沟通,填写信息,付款,获取订单状态,以及端上的现场互动等。
科研领域
需要远程采集观测的各种数据等。实验展示等。实验数据实时采集处理等。
几乎能想到的任何需要实时通信、点对点通信、或者分频道通信的场景,都尝试着去实现。
在实际做自己的应用之前,我先上手跑了一下官方的 demo,开启踩坑之旅。
准备
笔者体验环境:
- windows10 x64
- IntelliJ IDEA 2018.3.2 x64
- SDK
- jdk1.8
SDK 目录
解压 SDK,得到如下目录结构,我们后续会基于其中的samples : Agora-Signaling-Turorial-Java 来学习和理解server端SDK和api。
└─Agora_Signaling_Server_SDK_Java // SDK根目录├─lib // 信令的jar包├─libs-dep // 行令依赖的jar包└─samples // 一个栗子└─Agora-Signaling-Tutorial-Java├─gradle // 由此可以判断时gradle项目│ └─wrapper├─lib // 这里已经又全部需要的jar包了,需要用SDK中 lib、libs中的jar包覆盖└─src└─main└─java├─mainclass├─model└─tool
导入为idea项目
前面我们简单预览SDK目录,一个gradle项目。非常容易导入idea。这里就以idea搭建demo运行环境。
1.进入 Agora-Signaling-Tutorial-Java
2.右键–> Open Folder as InterlJ Idea project
3.等待导入完成,通常都很快
配置
1.配置SDK
确保SDK目录下的lib、libs-dep 中的所有jar包到项目的lib目录下。
2.查看并修改build.gradle,要注意其中第14行
dir: 'lib', include: ['* .jar']
修改为:
dir: 'lib', include: ['*.jar']
星号*后没有空格。修改后的build.gradle:
group 'com.agora'
version '1.0-SNAPSHOT'
apply plugin: 'java'
sourceCompatibility = 1.5
repositories {jcenter()
}
dependencies {testCompile group: 'junit', name: 'junit', version: '4.11'compile fileTree (dir: 'lib', include: ['*.jar'])
}
gradle配置发生变化时,idea提示 import Changes ,点一下 import Changes .
确保gradle成功引入了依赖jar包。
3.配置appid
tip: 这里需要注意, agora 有两种鉴权机制。直接用appid,或者使用token。为方便演示,我们直接用appid完成鉴权,但是,笔者也同时搬来了java的token算法。具体看 第 4 步介绍。
切换到 Pancages 视角,找到 tool/COnstant,注意 8 ~ 11 行 ,
static {//app_ids.add("Your_appId");//app_ids.add("Your_appId");
}
这里我们取消一行注释, 替换其中的Your_appId 为真实的appid。
static {//app_ids.add("Your_appId");app_ids.add("");
}
4.计算token
tips: 只有在开启app认证时,才会用到token。这里方便演示,笔者决定暂时不开启app认证。笔者仅仅模仿并贴出相关代码
具体实现:
package tool;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public class SignalingToken {public static String getToken(String appId, String certificate, String account, int expiredTsInSeconds) throws NoSuchAlgorithmException {StringBuilder digest_String = new StringBuilder().append(account).append(appId).append(certificate).append(expiredTsInSeconds);MessageDigest md5 = MessageDigest.getInstance("MD5");md5.update(digest_String.toString().getBytes());byte[] output = md5.digest();String token = hexlify(output);String token_String = new StringBuilder().append("1").append(":").append(appId).append(":").append(expiredTsInSeconds).append(":").append(token).toString();return token_String;}public static String hexlify(byte[] data) {char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};char[] toDigits = DIGITS_LOWER;int l = data.length;char[] out = new char[l << 1];// two characters form the hex value.for (int i = 0, j = 0; i < l; i++) {out[j++] = toDigits[(0xF0 & data[i]) >>> 4];out[j++] = toDigits[0x0F & data[i]];}return String.valueOf(out);}
}
更具体的可以参考 java版token算法实现
关于鉴权机制及算法 详情见
运行demo
1.在启动前,有必要来一起看看 mainclass目录。
启动类有两个, 一个是启动点对点通信server的, 另一个是频道消息。
怎么理解呢,其实很简单,点对点通信,你可以理解为俩人窃窃私语。频道通信则是群聊(像微信群)。
└─src└─main└─java├─mainclass│ MulteSignalObjectMain2.java // 频道消息 启动类│ SingleSignalObjectMain.java // 点对点通信 启动类│ WorkerThread.java // 核心业务流程
2.尝试通信
a.启动
选中 SingleSignalObjectMain.java --> ctrl + shift + f10
b.输入自己的accout
run 选项卡中已经提示你输入 account ,我们随便输入一个 Roman
后续可以尝试自己实现用户中心
c.选择模式并发送消息
然后, 会看到提示 successd
这里,先一起试试 点对点通信 ,输入 2 ,回车
我们输入聊天的对象,hello
顺便开个linux虚拟机运行linux客户端demo
互相发消息
这里比较奇怪,demo可能有些功能业务省略掉了,java端可以发点对点消息,却收不到。
尝试发频道消息,发现群聊频道模式完全没问题。
3.小结
启动demo没有什么难度,不过demo里的业务怎么样,需要大家花些心思来学习。
code review (java)
demo跑起来了,但是我们并不是很明白这个程序具体业务。换自己来写,可能还是一脸懵。所以,笔者决定review code,学习一下SDK用法。
文件src\main\java\tool\Constant.java中大部分写死的和预定义的参数值都在这里
package tool;import java.util.ArrayList;public class Constant {public static int CURRENT_APPID = 0;public static ArrayList<String> app_ids = new ArrayList();// 申明一些 命令,这些命令通常都是些常量public static String COMMAND_LOGOUT;public static String COMMAND_LEAVE_CHART;public static String COMMAND_TYPE_SINGLE_POINT;public static String COMMAND_TYPE_CHANNEL;public static String RECORD_FILE_P2P;public static String RECORD_FILE_CHANEEL;public static int TIMEOUT;public static String COMMAND_CREATE_SIGNAL;public static String COMMAND_CREATE_ACCOUNT;public static String COMMAND_SINGLE_SIGNAL_OBJECT;public static String COMMAND_MULTI_SIGNAL_OBJECT;public Constant() {}static {// 前面声明的变量名,这里复制// app_ids 是数组格式的,意味你可以添加多个appidapp_ids.add("073e6cb4f3404d4ba9ad454c6760ec0b"); // 一些命令 定义// 退出登陆COMMAND_LOGOUT = "logout";// 离开当前聊天绘画COMMAND_LEAVE_CHART = "leave";// 私聊模式输入2COMMAND_TYPE_SINGLE_POINT = "2";// 群聊模式输入3COMMAND_TYPE_CHANNEL = "3";// 缓存文件定义RECORD_FILE_P2P = "test_p2p.tmp";RECORD_FILE_CHANEEL = "test_channel.tmp";// 超时TIMEOUT = 20000;// 新建 一个signalCOMMAND_CREATE_SIGNAL = "0";// 新建一个用户COMMAND_CREATE_ACCOUNT = "1";// 进入点对点模式COMMAND_SINGLE_SIGNAL_OBJECT = "0";// 进入频道群聊模式COMMAND_MULTI_SIGNAL_OBJECT = "1";}
}
启动类
以 点对点 为例:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package mainclass;import tool.Constant;
// 一个点对点启动类
public class SingleSignalObjectMain {// 构造方法public SingleSignalObjectMain() {}// main 方法接受 字符串数组作为参数public static void main(String[] args) {// new 一个workerThread ,核心业务都在workerThread 类中WorkerThread workerThread = new WorkerThread(Constant.COMMAND_SINGLE_SIGNAL_OBJECT);// 启动这个workerThread 线程。 (new Thread(workerThread)).start();}
}
model目录中定义了一些数据类和类方法,比较容易理解。
main/java/mainclass/WorkerThread.java文件里定义了一个线程类,继承Runable。
限于篇幅,这里摘部分代码出来解读一下。
首先, WorkerThread类中定义:
private boolean mainThreadStatus = false; // 主线程状态 默认false
private String token = "_no_need_token"; // 默认未开启token认证,而是直接使用appid
private String currentUser; // 当前会话用户
private boolean timeOutFlag; // 超时标记,是否超时
private DialogueStatus currentStatus; // 当前消息状态
private HashMap<String, User> users; // 用户表
private HashMap<String, List<DialogueRecord>> accountDialogueRecords = null; // 账号会话记录
private HashMap<String, List<DialogueRecord>> channelDialogueRecords = null; // 频道会话记录
List<DialogueRecord> currentAccountDialogueRecords = null; // 当前账号会话记录
List<DialogueRecord> currentChannelDialogueRecords = null; // 当前频道会话记录
重点看一下构造方法
public WorkerThread(String mode) {currentMode = mode; //传入modeinit(); // 初始化String appid = Constant.app_ids.get(0); // 获取配置文件的里的app_id// 如果传入mode值等于COMMAND_SINGLE_SIGNAL_OBJECT的值(点对点),用appid new 一个信令,更新会话状态为为登陆状态// 否则判断是否为频道模式,更新状态。 这里,大家可以根据自己情况修改逻辑。// 这里有个疑问,两个分支里,为啥一个需要 new Signal 一个不需要呢?if (currentMode.equals(Constant.COMMAND_SINGLE_SIGNAL_OBJECT)) {sig = new Signal(appid);currentStatus = DialogueStatus.UNLOGIN;} else {if (currentMode.equals(Constant.COMMAND_MULTI_SIGNAL_OBJECT)) {currentStatus = DialogueStatus.SIGNALINSTANCE;}}
}
init() function
则初始化一个必要的需要交互输入来初始化的数据
run() function
会根据currentStatus的值来调用不同的业务函数
makeSignal()
中非常关键的一步
Signal signal = new Signal(appId); //用id实例化信令
joinChannel(String channelName)中用到LoginSession类和Channel类
public void joinChannel(String channelName) {final CountDownLatch channelJoindLatch = new CountDownLatch(1);// 实例化Channel 类 ,里面override几个事件监听Channel channel = users.get(currentUser).getSession().channelJoin(channelName, new Signal.ChannelCallback() {// 当加入频道时@Overridepublic void onChannelJoined(Signal.LoginSession session, Signal.LoginSession.Channel channel) {channelJoindLatch.countDown();}// 频道用户列表发生变化时@Overridepublic void onChannelUserList(Signal.LoginSession session, Signal.LoginSession.Channel channel, List<String> users, List<Integer> uids) {}// 收到频道消息时@Overridepublic void onMessageChannelReceive(Signal.LoginSession session, Signal.LoginSession.Channel channel, String account, int uid, String msg) {if (currentChannelDialogueRecords != null && currentStatus == DialogueStatus.CHANNEL) {PrintToScreen.printToScreenLine(account + ":" + msg);DialogueRecord dialogueRecord = new DialogueRecord(account, msg, new Date());currentChannelDialogueRecords.add(dialogueRecord);}}// 当频道用户加入会话时@Overridepublic void onChannelUserJoined(Signal.LoginSession session, Signal.LoginSession.Channel channel, String account, int uid) {if (currentStatus == DialogueStatus.CHANNEL) {PrintToScreen.printToScreenLine("..." + account + " joined channel... ");}}@Overridepublic void onChannelUserLeaved(Signal.LoginSession session, Signal.LoginSession.Channel channel, String account, int uid) {if (currentStatus == DialogueStatus.CHANNEL) {PrintToScreen.printToScreenLine("..." + account + " leave channel... ");}}@Overridepublic void onChannelLeaved(Signal.LoginSession session, Signal.LoginSession.Channel channel, int ecode) {if (currentStatus == DialogueStatus.CHANNEL) {currentStatus = DialogueStatus.LOGINED;}}});timeOutFlag = false;wait_time(channelJoindLatch, Constant.TIMEOUT, channelName);if (timeOutFlag == false) {// 未超时,加入频道users.get(currentUser).setChannel(channel);}}
这里篇幅有限,不能贴出全部代码。大家可以对着api文档来 着重看一下如何认证,如何登陆,如何收发消息。
后续,笔者会上传注释过的到github。
可能会遇到的问题及应对方法
1.demo的build.gradle 中多了一个空格,导致提示找不到lib
解决方法: * .jar --> *.jar
2.实例化signal时失败
解决方法: 检查appid是否正确,检查是否开启了token认证
如果开启了token认证,需要增加token计算算法,可以参考这个文档。
3.笔者发现两个启动类虽然默认启动命令值不一样,但是其实启动效果一样,都可以选择切换p2p或者channel模式。
基于声网 Agora 信令 SDK 开发聊天室应用(一)相关推荐
- 声网 agora php sdk,快速了解声网Agora SDK 3.0
声网 Agora Native SDK 3.0 ,以及 Web SDK 3.0.2 ,已经正式发布上线一段时间了. 新版本 SDK 采用了全新的系统架构和下一代实时编码传输技术,同时还新增了许多新功能 ...
- 声网Agora Native SDK 2.9.3 发布
新年伊始,开工大吉! 声网 Agora Native SDK 2.9.3 现在已经正式发布,并已更新至官网开发者中心的「SDK和应用下载」页面.新版本面向Android.iOS.macOS.Windo ...
- 4 分钟,快速了解声网 Agora SDK 3.0
声网 Agora Native SDK 3.0 ,以及 Web SDK 3.0.2 ,已经正式发布上线一段时间了.如果大家没时间看文字,可以通过这个视频快速了解一下. 新版本 SDK 采用了全新的系统 ...
- iOS开发-声网Agora Demo
iOS开发-声网Agora Demo 前言 开发准备 代码 关于其他详细的文档 前言 声网Agora是最近类似七牛云和腾讯云的直播视频类的付费SDK,官网上的Demo不是很易懂,所以下面举个例子. 开 ...
- 声网 Agora 的 2019
50+新增数据中心 300%全网带宽容量上涨 中国区支持百万大频道动态扩展能力 海外大频道扩容时间缩短50% 日分钟数超过6亿 支持 5G 网络下高清.大码率视频传输 移动端超分.感知视频编码.AI ...
- 基于声网的音视频SDK和FreeSWITCH开发WebRTC2SIP Gateway 方案和思路
为什么做这个? 今年初接到一个项目任务,客户要求在自己的音视频平台系统中集成webrtc功能(原系统是基于SIP协议开发的,已经稳定运行多年,有很多客户).在比对了多家RTC产品的效果后,.他们对声网 ...
- 使用声网的RTM SDK轻松给angular应用加上实时聊天功能
作者:陈畏民 源起 今年寒假的前半段时间, 在家捣鼓了一个情侣类web应用, 基于aspnetcore和angular搭建的; 寒假中实现了'告白', '相册', '说说', '纪念日'这些功能, 然 ...
- 基于声网 Flutter SDK 实现多人视频通话
前言 本文是由声网社区的开发者"小猿"撰写的Flutter基础教程系列中的第一篇.本文除了讲述实现多人视频通话的过程,还有一些 Flutter 开发方面的知识点.该系列将基于声网 ...
- 声网Agora SDK支持50ms超低延时耳返 适配主流手机机型
近年来,随着网络直播的火爆,直播唱歌成为了很多主播在直播间的必备技巧,同时全民K歌.唱吧等在线K歌软件的兴起,也让很多人足不出户也能享受K歌的乐趣,并成为越来越多人偏爱的在线娱乐方式.而不管是直播唱歌 ...
最新文章
- 2022-2028年中国床上用品行业投资分析及前景预测报告
- PHP安装parsekit扩展查看opcode
- 线程池之FixedThreadPool学习
- 这13个开源GIS软件,你了解几个?【转】
- Hi3516A开发--apt-get更新
- Java-eclipse快捷键及设置
- JAVA语言运算符(算数运算符、赋值运算符、比较运算符、逻辑运算符、三元运算)
- MySQL 表和列的注释的添加以及查看
- 在Linux中查找用户帐户信息和登录详细信息的11种方法
- C语言中的面向对象2
- 三菱J4伺服驱动器拨码
- ndk命令行编译so库
- 竞逐新能源汽车续航,背靠广汽的巨湾技研能否打好“技术牌”?
- 应用上云可以有多快?
- Google TensorFlow课程 编程笔记(10)———使用神经网络对手写数字进行分类
- 【2018焦作-E】Resistors in Parallel(思维+大数)
- 【LaTex】基础语法框架快速入门教程——Tex live+TexStudio简要安装及使用教程
- 富文本编辑器 vue-tiptap-wrap
- springboot 到底有什么魅力?
- 《Maven 实战》读书笔记(六) 聚合