@wanlingsdk/avatar-sdk
v0.1.10
Published
Wanling Avatar SDK - 虚拟人视频播放SDK,支持WebCodecs解码、音视频同步、实时语音对话
Maintainers
Readme
WanLing Avatar SDK
基于预渲染动作视频的虚拟人SDK,适合快速集成、低性能要求的场景。
特性
- 🎬 预渲染视频播放:支持 HTML5 Video 或 Canvas 渲染两种模式
- 🚀 0 闪屏连播:Canvas 模式使用 WebCodecs + mp4box.js 自解码自渲染,连播切换无闪烁
- 🎭 动作管理:支持idle、talk、wave、laugh等多种动作
- 🔄 无缝转场:支持fade、cut、blend等转场效果
- 📦 轻量级:无3D引擎依赖,纯JavaScript实现
- 🌐 跨平台:支持H5、iOS、Android(通过WebView)
- 📡 单流编排:与后端「单条流 + 按帧 append」对齐;
avatar_data含video_sequence与stream_seq:stream_seq=0表示首包/清空后写入,stream_seq>0表示追加到当前段列表,前端按currentFrame在段列表中选段播放。
文档
快速开始
安装
# 通过npm安装(待发布)
npm install @xhuman/video-sdk
# 或直接引入dist文件
<script src="https://cdn.example.com/xhuman-video-sdk.js"></script>基础使用
<!DOCTYPE html>
<html>
<head>
<title>XHuman Video Avatar Demo</title>
</head>
<body>
<div id="avatar-container"></div>
<input type="text" id="text-input" placeholder="输入消息...">
<button id="send-btn">发送</button>
<script src="./dist/xhuman-video-sdk.js"></script>
<script>
const avatar = new XHumanVideoSDK.VideoAvatar({
apiBaseUrl: 'http://localhost:8000',
characterId: 'default',
container: document.getElementById('avatar-container'),
autoplay: true
});
// 初始化
avatar.init().then(() => {
console.log('Avatar初始化成功');
});
// 发送消息
document.getElementById('send-btn').addEventListener('click', async () => {
const text = document.getElementById('text-input').value;
const sessionId = 'session_' + Date.now();
const result = await avatar.sendText(text, sessionId);
console.log('AI回复:', result.reply_text);
});
</script>
</body>
</html>API文档
VideoAvatar类
构造函数
const avatar = new VideoAvatar(config)参数:
apiBaseUrl(string): 后端API地址,默认http://localhost:8000characterId(string): 虚拟人角色IDcontainer(HTMLElement): 视频容器DOM元素autoplay(boolean): 是否自动播放,默认trueloop(boolean): 是否循环播放,默认falseuseCanvasPlayer(boolean): 是否使用 Canvas 播放器(WebCodecs 解码、Canvas 渲染),实现 0 闪屏连播,默认false
// 启用 Canvas 播放器(需浏览器支持 WebCodecs)
const avatar = new VideoAvatar({
container: document.getElementById('avatar-container'),
useCanvasPlayer: true // 连播切换时无闪屏、无抖动
});方法
init()
初始化Avatar,预加载基础动作视频。
await avatar.init();sendText(text, sessionId)
发送文本消息,获取AI回复和对应的动作视频。
const result = await avatar.sendText('你好', 'session_123');
// result: { success, reply_text, avatar_data, audio_base64 }playAction(actionData)
手动播放指定动作。
await avatar.playAction({
action: 'wave',
video_url: 'https://...',
transition: 'fade',
duration: 2.0
});setAction(action)
快速设置动作(使用预加载的视频)。
avatar.setAction('idle'); // 播放idle动作
avatar.setAction('talk'); // 播放talk动作connectTtsaSocket(options)
连接 TTSA 风格 WebSocket,接收 avatar_data / tts_audio 等。可选 onReady、onError 等回调。
数据晚到与错误码:当身体或音频数据晚于当前播放帧到达时,会通过 options.onError(err) 上报,数据仍会入队使用(身体段照常写入;音频会对齐 sf/ef 后入队以减轻音画错位)。错误对象格式:{ code, message, currentFrame?, sf?, delta? }。
BODY_DATA_EXPIRED:身体数据晚到(当前帧 > 数据起始帧且 > 10)。AUDIO_DATA_EXPIRED:音频数据晚到(当前帧 > 该块 sf),并自动做 sf/ef 对齐。
avatar.connectTtsaSocket({
url: 'http://localhost:8000',
room: 'room_1',
onReady: () => console.log('时钟已启动'),
onError: (err) => {
if (err.code === 'BODY_DATA_EXPIRED' || err.code === 'AUDIO_DATA_EXPIRED') {
console.warn('数据晚到', err.code, err);
} else {
console.error('TTSA 错误', err);
}
}
});外部数据通讯(页面 ↔ SDK)
SDK 提供统一的「接收页面数据」与「对外发送数据」接口,便于与宿主页面、大屏、H5 等多端联动。
接收页面数据(页面 → SDK)
setPageData(data):页面将当前上下文写入 SDK(如选中城市、用户 ID、大屏状态)。会与已有数据合并,发送文本时若后端支持可随send_text携带page_data。getPageData():获取当前缓存的页面数据副本。
// 页面传入上下文(如大屏选中的城市)
avatar.setPageData({ selectedCity: '乌鲁木齐', scene: 'pc' });
const data = avatar.getPageData(); // { selectedCity: '乌鲁木齐', scene: 'pc' }对外发送数据(SDK → 页面)
在 connectTtsaSocket(options) 中传入 onDataOut 回调,SDK 在关键节点推送数据,格式为 { type, payload }:
| type | 说明 | payload 示例 |
|------|------|--------------|
| reply_final | 回复文本流结束 | { text, sessionId, is_final: true } |
| state_change | 状态变更 | 服务端下发的 state 数据 |
| error | 错误 | { code, message } |
| interrupt | 服务端打断 | 打断事件数据 |
| sleep_state_change | 沉睡/唤醒状态变更 | { isSleeping, message } |
| visibility_change | 展示状态变更 | { visible, interaction_enabled } |
| broadcast_start | 播报开始 | { broadcast, queued_count } |
| broadcast_end | 播报结束 | { broadcast, reason, message } |
| broadcast_interrupted | 播报被打断 | { broadcast, reason, message } |
| broadcast_rejected | 播报被拒绝 | { broadcast, reason, message } |
| broadcast_queue_cleared | 播报队列已清空 | { reason, message, cleared } |
| broadcast_queue_change | 播报队列变化 | { current_context, active_broadcast, queued_count, queue } |
avatar.connectTtsaSocket({
url: 'http://localhost:8000',
room: 'room_1',
onDataOut: ({ type, payload }) => {
if (type === 'reply_final') console.log('回复完成', payload.text);
if (type === 'broadcast_start') console.log('播报开始', payload.broadcast?.id);
if (type === 'error') console.error('SDK 错误', payload);
},
onReady: () => console.log('时钟已启动'),
onError: (err) => console.warn('TTSA 错误', err)
});主动播报
SDK 提供独立的播报能力,具体业务何时调用由宿主页面决定。播报与聊天互斥:
- 聊天期间发起播报:自动打断聊天并切入播报
- 播报期间收到文本/语音:自动终止当前播报并切回聊天
- 播报内部支持优先级、队列和抢占
const broadcastId = avatar.broadcast({
text: '前方路段拥堵,请注意绕行',
priority: 80,
interrupt: true,
enqueue: true,
source: 'biz_warning',
metadata: { eventId: 'evt_001' }
});
avatar.cancelBroadcast(broadcastId); // 取消指定播报
avatar.cancelBroadcast(); // 取消当前活动播报
avatar.clearBroadcastQueue(); // 清空等待中的播报队列
const state = avatar.getBroadcastState();
console.log(state.currentContext, state.queuedCount);连接心跳与断连检测
SDK 当前维护两条实时连接:
SocketClient:基于socket.io-client,使用协议内建 heartbeatAsrStreamClient:原生WebSocket,使用业务层ping/pong
Socket.IO 链路无需业务方额外发心跳,只需监听连接状态事件即可:
connectdisconnectreconnect_attemptreconnect_failed
AsrStreamClient 已内置心跳检测:
- 默认每
2s发送一次ping:<timestamp> - 服务端返回
pong:<client_ts>:<server_ts_ms> - 连续一段时间未收到
pong时,状态先进入degraded - 超过
3个心跳周期未收到pong且没有任何服务端入站消息时,触发onError({ code: 'WS_HEARTBEAT_TIMEOUT' }) - 连接关闭后会自动重连,默认重连间隔
1s
可选配置:
const asr = new AsrStreamClient({
sessionId: 'room_1',
baseUrl: 'http://localhost:8000',
heartbeatIntervalMs: 2000,
heartbeatTimeoutMs: 6000,
reconnect: true,
reconnectDelayMs: 1000,
reconnectAttempts: Infinity,
onStatusChange: (status) => {
console.log('ASR status:', status);
}
});onStatusChange 可能收到的心跳相关状态:
connectingconnectedlisteningdegradedheartbeat_oktimeoutreconnectingstopped
动作列表
idle: 待机动作(默认循环播放)talk: 说话动作(配合TTS音频)wave: 挥手动作(打招呼/告别)nod: 点头动作(同意/理解)think: 思考动作(AI思考中)laugh: 大笑动作(开心/幽默)surprised: 惊讶动作(意外/惊喜)
项目结构
SDK-video/
├── src/
│ ├── index.js # SDK入口
│ ├── VideoAvatar.js # 核心类(编排走 WebSocket)
│ ├── CanvasVideoPlayer.js # 唯一播放器(WebCodecs+mp4box+Canvas)
│ └── TtsaSocketClient.js # Socket.IO 客户端(TTSA 协议)
├── examples/
│ ├── basic/ # 基础示例
│ └── advanced/ # 高级示例
├── dist/ # 构建产物
└── docs/ # 文档开发
# 安装依赖
npm install
# 开发模式
npm run dev
# 构建
npm run build许可证
MIT License
