写点什么

🏆【声网 Agora】「WebRTC- 如何搭建语音认证服务」

发布于: 2021 年 06 月 04 日
🏆【声网Agora】「WebRTC-如何搭建语音认证服务」

前提准备

拥有一个【Agora 账户】
  • 如果你还没有声网开发者账号,那么你需要在声网Agora 官网进行注册

  • 如果你已经注册过了声网开发者账号,那么可以通过声网官网直接登录账号

  • 选择 "项目管理 "下 "项目列表 "选项卡,点击蓝色的 "创建 "按钮,创建一个项目。(当提示使用 App ID+证书时,选择只使用 App ID。)记住你的 App ID,它将在开发 App 时用于授权你的请求。

  • 完成步骤后,即可拥有一个账号。

文档中心

声网 Agora 官方文档地址:https://docs.agora.io/cn

集成 Agora 音频 SDK,实现高音质语音通话。通过美声、音效、混音等功能,你可以轻松实现语聊房、线上 KTV、语音会议等场景。搭配服务端 RESTful API,你还可以实现踢人、查询用户列表等功能。

业务场景

语音通话可以实现纯语音的一对一单聊和多人群聊,不具备视频通话功能,包体积更小,适用于各种语音社交、语音会议等场景。

语音负责场景,主要包括:伴奏混音、播放音效文件、变声和混响、听声辨位、使用双声道和高音质以及修改原始音

频数据。

伴奏混音
  • 业务实现:将本地或在线的音频和用户声音,同时发送并播放给频道内其他用户。

  • 适用场景:在线合唱,音乐互动课堂。

播放音频
  • 业务实现:可以播放指定的音效文件,支持设置音效的音调和空间位置。

  • 适用场景:棋牌游戏。

变声和混响
  • 业务实现:提供多种预置的变声和混响效果,同时支持灵活调整用户声音的音调、均衡及混响效果。

  • 适用场景:一起 KTV,语音聊天室变声。

听声辨位
  • 业务实现:设置远端用户声音出现的位置,增加游戏角色的方位感,还原真实游戏场景。

  • 适用场景:CS、CF、吃鸡游戏以及相关使命召唤等。

听声辨位
  • 业务实现:设置远端用户声音出现的位置,增加游戏角色的方位感,还原真实游戏场景。

  • 适用场景:CS、CF、吃鸡游戏以及相关使命召唤等。

双声道/高音质
  • 业务实现:支持高音质、双声道的音频设置。

  • 适用场景:音乐教学,FM 音频电台。

修改原始音频数据
  • 业务实现:可支持变声,支持获取媒体引擎的原始语音,对原始数据进行处理

  • 适用场景:语音聊天室变声

关键特性
  • SDK 包体积:3.14 ~ 11.28 MB

  • 音频属性

  • 音频采样率:16 kHz - 48 kHz

  • 支持单、双声道

  • 音频抗丢包率:上下行抗丢包率 80%a

平台兼容

语音通话支持 iOS、Android、Windows、macOS、Electron、Unity、Web、小程序,并支持平台间互通,具体的兼容性要求见下表。

桌面端

Web SDK 对桌面端浏览器的支持情况详见下表:

Web SDK2.5 及以上版本支持 Windows XP 平台的 Chrome 49 版本浏览器(仅支持 VP8 编解码,不能与 Native SDK 互通)。Web SDK 理论上还支持 360 极速浏览器,但未经过验证,不保证全部功能正常工作。

移动端

Web SDK 对移动端浏览器的支持情况受到具体设备和浏览器的限制:

  • 在 Android 4.1+ 上,Web SDK 支持 Google Chrome 58 及以上版本,且 Agora 建议使用 VP8 编解码格式。这是由于 Android Chrome 对 H.264 的支持依赖硬件,而部分 Android 设备不支持 H.264 编解码格式。

  • 在 iOS 11+ 上,Web SDK 支持 Safari 11 及以上版本。但是由于 iOS Safari 存在较多已知问题,Agora 不推荐使用。你可以使用 Agora RTC iOS SDK 在 iOS 上实现实时音视频功能。

除上述浏览器外,对于移动端的一些应用内置浏览器,Web SDK 的支持情况较为复杂,详见移动端如何使用 Agora Web SDK?

服务端开发流程

使用 Token 鉴权

使用 Token 鉴权」是指在用户访问你的系统前,对其进行身份校验。用户在使用 Agora 服务,如加入音视频通话或登录信令系统时,Agora 使用 Token 对其鉴权。

本文展示如何在服务端部署一个 Token 生成器,以及如何搭建一个使用 Token 鉴权的客户端。

鉴权原理

下图展示了鉴权的基本流程:

图片来源:https://web-cdn.agora.io/docs-files/1622017307186

Token 在 app 服务器上生成,其最大有效期为 24 小时。当用户从你的 app 客户端连接至 Agora 频道时,Agora 平台会读取该 Token 中包含的信息,并进行校验。Token 包含以下信息:

  • Agora 控制台创建项目时生成的 App ID

  • 项目的 App 证书

  • 频道名

  • 用户 ID

  • 用户权限,如是否能发流或收流

  • Token 过期的 Unix 时间戳

鉴权流程

代码 SDK 地址:Tools/DynamicKey/AgoraDynamicKey at master · AgoraIO/Tools (github.com)

获取 App ID 及 App 证书

本节介绍如何获取生成 Token 所需的安全信息,如你的项目的 App ID 及 App 证书。

(1) 获取 App ID

Agora 自动为每一个项目分配一个 App ID 作为该项目的唯一标识。

Agora 控制台 Project Management 页面中找到你的项目,点击 App ID 右边的“眼睛”图标即可复制 App ID。

图片来源:https://web-cdn.agora.io/docs-files/1602646621028

(2) 获取 App 证书

点击 Edit,进入 Edit Project 页面。 点击“眼睛”图标即可复制 App 证书。

图片来源:https://web-cdn.agora.io/docs-files/1592535534341

部署 Token 服务器

Token 需要在你的服务端部署生成。当客户端发送请求时,服务端部署的 Token Generator 会生成相应的 Token,再发送给客户端。

Token 生成相关的 token 信息(SDK)

SDK 服务实现:Agora.io (github.com),如果需要其他实现,可以参考该 github 项目的其他工具

package io.agora.sample;
import io.agora.media.RtcTokenBuilder;import io.agora.media.RtcTokenBuilder.Role;
public class RtcTokenBuilderSample { static String appId = "970CA35de60c44645bbae8a215061b33"; static String appCertificate = "5CFd2fd1755d40ecb72977518be15d3b"; static String channelName = "7d72365eb983485397e3e3f9d460bdda"; static String userAccount = "2082341273"; static int uid = 2082341273; static int expirationTimeInSeconds = 3600; public static void main(String[] args) throws Exception { RtcTokenBuilder token = new RtcTokenBuilder(); int timestamp = (int)(System.currentTimeMillis() / 1000 + expirationTimeInSeconds); String result = token.buildTokenWithUserAccount(appId, appCertificate, channelName, userAccount, Role.Role_Publisher, timestamp); System.out.println(result); result = token.buildTokenWithUid(appId, appCertificate, channelName, uid, Role.Role_Publisher, timestamp); System.out.println(result); result = token.buildTokenWithUid(appId, appCertificate, channelName, uid, timestamp, timestamp, timestamp, timestamp); System.out.println(result); result = token.buildTokenWithUserAccount(appId, appCertificate, channelName, userAccount, timestamp, timestamp, timestamp, timestamp); System.out.println(result); }}
复制代码


现在以 Java 语言为例,还有其他的案例请见:raysandeep/AgoraToken (github.com)

具体方案可参考:使用Java构建Agora令牌服务器 - 专栏 - 声网 Agora RTC 开发者社区

Token 客户端介入(Http)

下列代码实现了 HTTP 基本认证并使用服务端 RESTful API 发送一个简单的请求,获取所有的 Agora 项目信息:

import java.io.IOException;import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;import java.util.Base64;

// 基于 Java 实现的 Token 认证示例,使用 RTM 的用户事件 RESTful APIpublic class Base64Encoding {
public static void main(String[] args) throws IOException, InterruptedException {
// RTM Token String tokenHeader = "Your RTM token"; // 生成 RTM Token 时使用的 user ID String uidHeader = "test_user";
HttpClient client = HttpClient.newHttpClient();

// 构建请求对象 HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.agora.io/dev/v2/project/<Your App ID>/rtm/vendor/user_events")) .GET() // 在 header 中添加 x-agora-token 字段 .header("x-agora-token", tokenHeader ) // 在 header 中添加 x-agora-uid 字段 .header("x-agora-uid", uidHeader) .header("Content-Type", "application/json") .build(); // 发送请求 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body()); }}
复制代码


下列示例代码实现了 HTTP 基本认证并使用服务端 RESTful API 发送一个简单的请求,获取所有的 Agora 项目信息:

import java.io.IOException;import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;import java.util.Base64;

// 基于 Java 实现的 HTTP 基本认证示例,使用 RTC 的服务端 RESTful APIpublic class Base64Encoding {
public static void main(String[] args) throws IOException, InterruptedException {
// 客户 ID final String customerKey = "Your customer key"; // 客户密钥 final String customerSecret = "Your customer secret";
// 拼接客户 ID 和客户密钥并使用 base64 编码 String plainCredentials = customerKey + ":" + customerSecret; String base64Credentials = new String(Base64.getEncoder().encode(plainCredentials.getBytes())); // 创建 authorization header String authorizationHeader = "Basic " + base64Credentials;
HttpClient client = HttpClient.newHttpClient();
// 创建 HTTP 请求对象 HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.agora.io/dev/v1/projects")) .GET() .header("Authorization", authorizationHeader) .header("Content-Type", "application/json") .build(); // 发送 HTTP 请求 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body()); }}
复制代码

语音通信服务端功能

除集成在客户端的音频/视频 SDK,Agora 还提供用于管理实时音视频频道的服务端 API,包括:

  • 频道管理 RESTful API:通过你的业务服务器向 Agora 服务器发送 HTTPS 请求,管理频道内的用户和查询频道信息。

  • 频道事件回调(Webhook):开通 Agora 消息通知服务后,当订阅的事件发生时,Agora 服务器会以 HTTPS 请求的形式向你的服务器发送通知,用于实时监控频道状态。

Agora 频道管理 RESTful API 提供以下功能:

封禁用户权限

Agora 频道管理 RESTful API 提供以下功能:

查询在线频道信息

Agora 频道管理 RESTful API 提供以下功能:

频道事件消息通知服务

Agora 提供频道事件消息通知服务,用于实时同步实时通信(RTC)业务中的频道状态。

开通消息通知服务后,当订阅的频道事件发生时,Agora RTC 业务服务器会将事件消息发送给 Agora 消息通知服务器,然后 Agroa 消息通知服务器会通过 HTTPS POST 请求方法将事件通知投递给你的服务器。

开通消息通知服务

功能配置

  1. 希望开通消息通知服务的业务,即实时音视频通信业务。

  2. 希望监听的频道事件,详见实时音视频通信频道事件类型


如需配置 QPS (Query Per Second) 较高的事件,如实时通信中观众加入或离开直播频道,请确保你的服务器有足够的处理能力。


  1. 接收消息通知的 HTTPS 服务器地址。

  • 为提高安全性,Agora 消息通知服务不再支持 HTTP 服务器地址。

  • 为降低消息投递的延时,Agora 建议你的服务器支持 HTTPS 连接重用,即 keep-alive 模式,并进行如下设置:MaxKeepAliveRequests:大于等于 100。KeepAliveTimeout:大于等于 10 秒。

  • 你的消息通知接收服务器所在的区域。Agora 会根据你提供的区域就近接入 Agora 节点服务器。目前,Agora 消息通知服务器部署在以下区域:

  • cn:中国

  • sea:东南亚

  • na:美国

  • eu:欧洲

获取密钥

为提高通信安全,Agora 消息通知服务使用签名机制验证身份。配置消息通知服务时,Agora 为你生成用于验证签名的密钥(secret),你需要向 Agora 技术支持获取并保存这个密钥。关于如何使用密钥验证签名,详见验证签名

配置测试

配置完成后,你可以让 Agora 技术支持帮你测试该配置。如果测试成功,即可正式开通该服务。

消息通知回调格式与内容

成功开通 Agora 消息通知服务后,当订阅的频道事件发生时,Agora 消息服务器会以 HTTPS POST 请求的形式向你的服务器发送消息通知回调。频道事件消息回调的格式与内容,详见频道事件回调

消息通知回调响应

接收到消息通知回调后,你的服务器需要在 10 秒内对 Agora 消息服务器作出响应。响应包体格式为 JSON,包体内容不作要求。


Agora 消息服务器发送通知后的 10 秒内,如果没有收到你的服务器的响应或响应状态码不是 200,会认为消息通知失败。失败后,Agora 消息通知服务器会立即重新发送消息通知,投递间隔随着重试次数的上升逐渐增加,直到第一次投递的 30 分钟后停止投递。

频道回调机制

Agora 提供频道事件消息通知服务,用于实时同步实时通信(RTC)业务中的频道状态。

开通消息通知服务后,当订阅的频道事件发生时,Agora RTC 业务服务器会将事件消息发送给 Agora 消息通知服务器,然后 Agroa 消息通知服务器会通过 HTTPS POST 请求方法将事件通知投递给你的服务器。

频道事件回调

Agora 消息通知服务器以 HTTPS POST 请求方法向你的服务器发送频道事件消息通知回调。数据格式为 JSON,字符编码为 UTF-8,签名算法为 HMAC/SHA1 或 HMAC/SHA256。

请求的 Header

消息通知回调的 header 中包含以下字段:

请求的 Body

消息通知回调的请求包体包含以下字段:

消息通知回调的请求包体示例:

{    "noticeId": "2000001428:4330:107",    "productId": 1,    "eventType": 101,    "notifyMs": 1611566412672,    "payload": {...}}
复制代码


频道事件类型

Agora 消息通知服务可以通知实时通信业务中的以下频道事件类型:

具体参数类型详情可见:频道事件回调 (agora.io)

验证签名

为提高 Agora 消息服务器和你的服务器之间的通信安全,Agora 使用签名机制进行身份验证。签名验证流程如下:

  1. 在配置 Agora 消息通知服务时,Agora 会生成一个密钥(secret)。你需要在开通服务时,向 Agora 技术支持获取并保存该密钥。

  2. 当 Agora 向你的服务器发送消息通知回调时,会使用密钥通过 HMAC/SHA1 和 HMAC/SHA256 算法生成签名值,并分别添加在 HTTPS 请求 header 的 Agora-Signature 和 Agora-Signature-V2 字段中。

  3. 收到回调后,你可以使用密钥和请求包体里的参数,选用 HMAC/SHA1 或 HMAC/SHA256 算法计算签名值,以验证 Agora-Signature 或 Agora-Signature-V2

Java 实现客户端解析数据案例

HMAC/SHA1

import javax.crypto.Mac;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;public class HmacSha {    // 将加密后的字节数组转换成字符串    public static String bytesToHex(byte[] bytes) {        StringBuffer sb = new StringBuffer();        for (int i = 0; i < bytes.length; i++) {            String hex = Integer.toHexString(bytes[i] & 0xFF);            if (hex.length() < 2) {                sb.append(0);            }             sb.append(hex);        }         return sb.toString();    }    //HMAC/SHA1 加密,返回加密后的字符串    public static String hmacSha1(String message, String secret) {        try {            SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(                        "utf-8"), "HmacSHA1");            Mac mac = Mac.getInstance("HmacSHA1");            mac.init(signingKey);             byte[] rawHmac = mac.doFinal(message.getBytes("utf-8"));            return bytesToHex(rawHmac);        } catch (Exception e) {            throw new RuntimeException(e);        }    }     public static void main(String[] args) {        //拿到消息通知的 raw request body 并对其计算签名,也就是说下面代码中的 request_body 是反序列化之前的 binary byte array,不是反序列化之后的 object        String request_body = "{\"eventMs\":1560408533119,\"eventType\":10,\"noticeId\":\"4eb720f0-8da7-11e9-a43e-53f411c2761f\",\"notifyMs\":1560408533119,\"payload\":{\"a\":\"1\",\"b\":2},\"productId\":1}";        String secret = "secret";        System.out.println(hmacSha1(request_body, secret)); //033c62f40f687675f17f0f41f91a40c71c0f134c    }}
复制代码


HMAC/SHA256

import javax.crypto.Mac;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;public class HmacSha {    // 将加密后的字节数组转换成字符串    public static String bytesToHex(byte[] bytes) {        StringBuffer sb = new StringBuffer();        for (int i = 0; i < bytes.length; i++) {            String hex = Integer.toHexString(bytes[i] & 0xFF);            if (hex.length() < 2) {                sb.append(0);            }             sb.append(hex);        }         return sb.toString();    }    //HMAC/SHA256 加密,返回加密后的字符串    public static String hmacSha256(String message, String secret) {        try {            SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(                        "utf-8"), "HmacSHA256");            Mac mac = Mac.getInstance("HmacSHA256");            mac.init(signingKey);             byte[] rawHmac = mac.doFinal(message.getBytes("utf-8"));            return bytesToHex(rawHmac);        } catch (Exception e) {            throw new RuntimeException(e);        }    }     public static void main(String[] args) {        //拿到消息通知的 raw request body 并对其计算签名,也就是说下面代码中的 request_body 是反序列化之前的 binary byte array,不是反序列化之后的 object        String request_body = "{\"eventMs\":1560408533119,\"eventType\":10,\"noticeId\":\"4eb720f0-8da7-11e9-a43e-53f411c2761f\",\"notifyMs\":1560408533119,\"payload\":{\"a\":\"1\",\"b\":2},\"productId\":1}";        String secret = "secret";        System.out.println(hmacSha256(request_body, secret)); //033c62f40f687675f17f0f41f91a40c71c0f134c    }}
复制代码


发布于: 2021 年 06 月 04 日阅读数: 151
用户头像

我们始于迷惘,终于更高水平的迷惘。 2020.03.25 加入

🏆 【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 🤝未来我们希望可以共同进步🤝

评论

发布
暂无评论
🏆【声网Agora】「WebRTC-如何搭建语音认证服务」