快速发起语音通话
本文档用于说明如何快速集成客户端 SDK (ZEGO Express SDK)并实现与智能体进行语音互动。
前提条件
- 已在 ZEGO 控制台 创建项目,并申请有效的 AppID 和 AppSign,详情请参考 控制台 - 项目信息。
- 已联系 ZEGO 技术支持获取针对 AI Agent 优化的 ZEGO Express SDK,并集成到您的项目中。
- 已按 业务后台快速开始指引 集成了 AI Agent 相关服务端 API。
示例代码
以下是接入实时互动 AI Agent API 的业务后台示例代码,您可以参考示例代码来实现自己的业务逻辑。
包含最基本的获取 ZEGO Token、注册智能体、创建智能体实例、删除智能体实例等能力。
以下是客户端示例代码,您可以参考示例代码来实现自己的业务逻辑。
包含最基本的登录、推流、拉流、退出房间等能力。
以下视频演示了如何跑通服务端和客户端(Web)示例代码并跟智能体进行语音互动。
整体业务流程
- 服务端,参考业务后台快速开始文档跑通业务后台示例代码,部署好业务后台
- 接入实时互动 AI Agent API 管理智能体。
- 客户端,跑通示例代码
- 通过业务后台创建和管理智能体。
- 集成 ZEGO Express SDK 完成实时通信。
完成以上两个步骤后即可实现将智能体加入房间并与真实用户进行实时互动。
核心能力实现
集成 ZEGO Express SDK
请参考 集成 SDK > 方式 1 使用 npm 集成针对 AI Agent 优化的 ZEGO Express SDK 版本。集成 SDK 后按以下步骤初始化 ZegoExpressEngine。
必须使用下载 SDK 及 Demo页面针对 AI Agent 优化的 ZEGO Express SDK 版本,否则无法正常显示字幕。
1 实例化 ZegoExpressEngine
2 检查系统要求(WebRTC 支持和麦克风权限)
import { ZegoExpressEngine } from "zego-express-engine-webrtc";
const appID = 1234567 // 从即构控制台获取
const server = 'xxx' // 从即构控制台获取
// 实例化 ZegoExpressEngine传入appId和server等配置
// !mark
const zg = new ZegoExpressEngine(appID, server);
// 检查系统要求
// !mark
const checkSystemRequirements = async () => {
// 检测是否支持webRTC
const rtc_sup = await zg.checkSystemRequirements("webRTC");
if (!rtc_sup.result) {
// 浏览器不支持webrtc
}
// 检测是否开启麦克风权限
const mic_sup = await zg.checkSystemRequirements("microphone");
if (!mic_sup.result) {
// 未开启麦克风权限
}
}
checkSystemRequirements()通知业务后台开始通话
可在客户端真实用户进入房间后立即通知业务后台开始通话,异步调用可加降低通话接通时间。业务后台收到开始通话通知后,使用与客户端相同的 roomID 及关联的 userID 和 streamID 创建智能体实例,这样智能体就能与真实用户在同一个房间内进行相互推拉流实现语音互动。
// 通知业务后台开始通话
async function startCall() {
try {
// 后台在/api/startn接口中实际调用createAgentInstance接口
// !mark
const response = await fetch(`${YOUR_SERVER_URL}/api/start`, { // YOUR_SERVER_URL 为您的业务后台地址
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
});
const data = await response.json();
console.log('开始通话结果:', data);
return data;
} catch (error) {
console.error('开始通话失败:', error);
throw error;
}
}用户进入房间并推流
真实用户登录房间后推流。
登录用的 token 需要从您的业务后台获取,请参考完整示例代码。
请确保 roomID、userID、streamID 在一个 ZEGO APPID 下是唯一的。
- roomID: 由用户自己定义生成规则,会用来登录 Express SDK 的房间。仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', ''。如果需要与 Web SDK 互通,请不要使用 '%'。
- userID: 长度不超过32字节。仅支持数字,英文字符 和 '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', ''。如果需要与 Web SDK 互通,请不要使用 '%'。
- streamID: 长度不超过256字节。仅支持数字,英文字符 和 '-', '_'。
const userId = "" // 登录 Express SDK房间用户ID
const roomId = "" // RTC 房间 ID
const userStreamId = "" // 用户推流 ID
async function enterRoom() {
try {
// 生成 RTC Token [参考文档](https://doc-zh.zego.im/article/7646)
const token = await Api.getToken();
// 登录房间
await zg.loginRoom(roomId, token, {
userID: userId,
userName: "",
});
// 创建本地音频流
const localStream = await zg.createZegoStream({
camera: {
video: false,
audio: true,
},
});
if (localStream) {
// !mark(1:2)
// 推送本地流
await zg.startPublishingStream(userStreamId, localStream);
}
} catch (error) {
console.error("进入房间失败:", error);
throw error;
}
}
enterRoom()拉智能体流
默认只有一个真实用户及智能体在同一个房间内,所以拉流时默认新增的就是智能体流。
// 监听远端流更新事件
function setupEvent() {
zg.on("roomStreamUpdate",
async (roomID, updateType, streamList) => {
if (updateType === "ADD" && streamList.length > 0) {
try {
for (const stream of streamList) {
// 拉智能体流
// !mark
const mediaStream = await zg.startPlayingStream(stream.streamID);
if (!mediaStream) return;
const remoteView = await zg.createRemoteStreamView(mediaStream);
if (remoteView) {
// 这里需要页面上有个id为remoteSteamView的容器接收智能体流 [参考文档](https://doc-zh.zego.im/article/api?doc=Express_Video_SDK_API~javascript_web~class~ZegoStreamView)
remoteView.play("remoteSteamView", {
enableAutoplayDialog: false,
});
}
}
} catch (error) {
console.error("拉流失败:", error);
}
}
}
);
}恭喜你🎉!完成这一步骤后,您已经可以用语音问智能体任何问题,智能体都会用语音回答您的问题!
退出房间结束通话
客户端调用退出登录接口退出房间,并停止推拉流。同时通知业务后台本次通话结束。业务后台收到结束通话通知后会删除智能体实例,智能体实例会自动退出房间并停止推拉流。这样一次完整的互动就结束了。
// 退出房间
async function stopCall() {
try {
// !mark
const response = await fetch(`${YOUR_SERVER_URL}/api/stop`, { // YOUR_SERVER_URL 为您的业务后台地址
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
});
const data = await response.json();
console.log('结束通话结果:', data);
return data;
} catch (error) {
console.error('结束通话失败:', error);
throw error;
}
}
stopCall();
zg.destroyLocalStream(localStream);
// !mark
zg.logoutRoom();以上就是您实现与智能体进行实时语音互动的完整核心流程。
ZEGO Express SDK 最佳配置实践
为了获得最佳的音频通话体验,建议按照以下最佳实践配置 ZEGO Express SDK。这些配置可以显著提升智能体语音交互的质量。
- 开启传统音频 3A 处理(回声消除AEC、自动增益控制AGC、噪声抑制ANS)
- 设置房间的使用场景为高品质语聊房场景,SDK 会针对不同的场景采取不同的优化策略
- 配置音量闪避,避免声音冲突
- 推流时,设置推流参数配置自动切换为可用的
videoCodec
// 引入必要的模块
import { ZegoExpressEngine } from "zego-express-engine-webrtc";
import { VoiceChanger } from "zego-express-engine-webrtc/voice-changer";
// 引入音量闪避插件包,请使用 3.11.0-aiagent.187.187 版本
// !mark(1:2)
import { AudioRendererManager } from "/AudioRendererManager/AudioRendererManager";
import { MediaElementRenderer } from "/AudioRendererManager/mediaElementRenderer";
// 加载音频处理模块,需要在 new ZegoExpressEngine 前调用
ZegoExpressEngine.use(VoiceChanger);
// 实例化 ZegoExpressEngine,设置房间的使用场景为高品质语聊房场景
// !mark
const zg = new ZegoExpressEngine(appid, server, { scenario: 7 })
// 传统音频 3A 处理,SDK 默认开启
// 创建本地媒体流
const localStream = await zg.createZegoStream();
// 开启音量闪避
zg.callExperimentalAPI({
method: "enableVolumeDucking",
params: {
localStream,
enable: true
}
});
// 将播放器传入音量闪避插件包
let renderer;
zg.callExperimentalAPI({ method: "getAudioContext" }).then((ac) => {
const audioMgr = AudioRendererManager.create(ac);
// 获取播放器元素
const audio = document.querySelector("audio");
renderer = audioMgr.getMediaElementRenderer(audio);
});
// 注册音量闪避更新回调
zg.callExperimentalAPI({ method: "onVolumeDuckingUpdate", params: {} });
zg.on("recvExperimentalAPI", (result) => {
const { method, content } = result;
if (method === "onVolumeDuckingUpdate") {
console.warn("onVolumeDuckingUpdate", content.gain);
// 设置智能体流音量为回调返回的 content.gain,假设 remoteView 为你在步骤 拉智能体流 时创建的 remoteView
remoteView.setVolume(content.gain * 100); // volume 取值范围 [0,100]
// 设置播放器音量为回调返回的 content.gain
renderer.setVolume(content.gain * 100); // volume 取值范围 [0,100]
}
});
// 推送本地媒体流,需要设置自动切换为可用的 videoCodec
await zg.startPublishingStream(userStreamId, localStream, {
// !mark
enableAutoSwitchVideoCodec: true,
});
// 检查系统要求
async function checkSystemRequirements() {
// 检测是否支持WebRTC
const rtcSupport = await zg.checkSystemRequirements("webRTC");
if (!rtcSupport.result) {
console.error("浏览器不支持WebRTC");
return false;
}
// 检测麦克风权限
const micSupport = await zg.checkSystemRequirements("microphone");
if (!micSupport.result) {
console.error("未获得麦克风权限");
return false;
}
return true;
}其他优化建议
- 浏览器兼容性:推荐使用 Chrome、Firefox、Safari 等现代浏览器的最新版本
- 网络环境:确保网络连接稳定,建议使用有线网络或信号良好的Wi-Fi
- 音频设备:使用质量较好的麦克风和扬声器
- 页面优化:避免在同一页面运行过多JavaScript任务,可能会影响音频处理性能
- HTTPS环境:在生产环境中使用HTTPS协议,以确保获取麦克风权限
监听异常回调
点击查看监听异常回调指引。监听回调中 Event 为 Exception 的事件。通过 Data.Code 和 Data.Message 可以快速定位问题。
