news 2026/7/3 4:01:16

CosyVoice 双向流式 streamingCall() — 前后端总体方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CosyVoice 双向流式 streamingCall() — 前后端总体方案

CosyVoice 双向流式streamingCall()— 前后端总体方案

在保留现有LLM 流式type=content的前提下,把 TTS 从「整段call()+ OSS URL」升级为CosyVoice 双向 WebSocket + 音频帧直推前端,并保证语音失败不影响文字


一、现状 vs 目标

维度现状目标
文字百炼streamCalltype=content不变
TTS APIcall(整段)阻塞streamingCall(delta)+streamingComplete()
分句本地VoiceStreamingSegmentBufferCosyVoice 服务端自动分句(可去掉本地缓冲)
推前端voiceChunk.voiceUrl(OSS)音频帧(Base64 或 WS Binary)+ 可选短 URL 降级
落库段级 OSS + merge →ext.voiceUrl内存攒帧 → 结束 merge 上传一次
complete等 TTS 队列finishAndAwait文字结束即发 complete,TTS 异步收尾

二、总体架构

CosyVoice WSS streamingCall百炼 Agent streamCallMobileImControllerask-ai WebSocket小程序/H5CosyVoice WSS streamingCall百炼 Agent streamCallMobileImControllerask-ai WebSocket小程序/H5loop[LLM 流式]promptprocessWebSocketAskAi创建 SpeechSynthesizer+callbackchatStreamForWebSocketdeltatype=contentstreamingCall(delta)onEvent audioFrametype=voiceFrame全文结束type=textComplete 或 complete(无语音)streamingComplete()onCompletemerge帧→WAV→OSS→exttype=voiceComplete

原则

  1. 文字与语音解耦:content 先推;TTS 异常只 catch 打日志,不中断 LLM。
  2. 一问一 CosyVoice 连接:每问答一个SpeechSynthesizer,禁止单例共享。
  3. 文本单线程喂 TTS:LLM delta 入队,单线程streamingCall,避免多线程同实例。
  4. 出站串行:同一WebSocketSession的 content / voiceFrame 走per-connection 发送队列

三、后端方案

3.1 模块划分

模块职责
AliyunAgentServiceImpl不变:推content+onContentDelta
CosyVoiceStreamingSession(新)管理一条 WSS:streamingCall/streamingComplete/ callback / close
VoiceSynthesisService新增openStreamingSession(voiceId, callback),配置 WSS 端点
ImStreamingVoicePushSession(重构)去掉call()+段级 OSS;改为转发 delta + 收帧推前端 + 攒帧 merge
WebSocketOutboundQueue(新)同一连接 Text/Binary 串行 send
MobileImController创建/销毁 session;LLM 结束后先发 complete,TTS 异步 finalize

3.2 CosyVoice 会话生命周期

// 问答开始(有 doctorId + voiceId + 连接可用)SpeechSynthesisParamparam=builder().apiKey(...).model("cosyvoice-v2")// 与复刻音色一致.voice(voiceId).format(PCM_22050HZ_MONO_16BIT)// 或 MP3,流式推荐 PCM/MP3.build();SpeechSynthesizersynthesizer=newSpeechSynthesizer(param,callback);// LLM 每个 delta(onContentDelta,try-catch)textFeederQueue.offer(delta);// 单线程 consumer → synthesizer.streamingCall(delta)// LLM 结束synthesizer.streamingComplete();await onComplete/latch;// merge + 落库 + closesynthesizer.getDuplexApi().close(1000,"bye");

配置新增

aliyun:voice:api-key:sk-xxxmodel:cosyvoice-v2websocket-url:wss://{workspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference

SDK 建议≥ 2.22.0getOutput()句子事件);当前 2.19.4 可先 PoC。

3.3 与 LLM 的衔接

onContentDelta(delta): 1. outboundQueue.send(content) // 已在 Agent 层完成 2. cosyVoiceSession.feedText(delta) // 非阻塞入队 chatStreamForWebSocket 返回后: 1. updateBotMessageAfterAiReply 2. outboundQueue.send({ type: "textComplete" }) // 或带 complete 3. cosyVoiceSession.finishAsync() // streamingComplete + 不阻塞主线程 4. 环信 / 告警 等(不依赖 TTS)

3.4 推前端协议(建议)

文字(不变)

{"type":"content","content":"增量","messageId":"...","timestamp":123}

音频帧(新增,推荐 JSON+Base64 便于小程序)

{"type":"voiceFrame","messageId":"429476821505122304","seq":12,"format":"pcm","sampleRate":22050,"channels":1,"bitDepth":16,"sentenceIndex":0,"event":"sentence-synthesis","data":"base64...","timestamp":123}

可选:句子边界(来自result.getOutput()

{"type":"voiceSentence","messageId":"...","sentenceIndex":0,"text":"...","event":"sentence-end"}

结束

{"type":"voiceComplete","messageId":"...","hasVoice":true,"voiceUrl":"https://.../merged.wav"}{"type":"complete","messageId":"...","timestamp":123}
消息时机
contentLLM 流式
voiceGeneratingTTS 连接建立(可选)
voiceFrameCosyVoiceonEventaudioFrame
textCompleteLLM 结束(不等 TTS
voiceCompleteTTSonComplete+ merge 落库后
completetextComplete同发,或 voice 可选

降级:帧推送失败或小程序不支持流式播放时,保留短 MP3 分片 URLvoiceChunk兼容。

3.5 落库

onEvent: audioFrames.add(frame) onComplete: bytes = concat(frames) 或 decode PCM → WAV mergedUrl = upload OSS voice/merged ext: { hasVoice, voiceUrl, voiceFormat, voiceId }

段级 OSS 可取消,只保留最终 merge 一次

3.6 失败与隔离

失败处理
无音色 / 无 doctorId不建 TTS,仅 content + complete
streamingCall/ CosyVoice 报错日志 +voiceComplete(hasVoice=false)不影响已推 content
单帧推送失败日志,继续后续帧
merge/OSS 失败ext.voiceUrl,实时播放仍可能完整
23s 无新文本超时关 TTS;LLM 若仍输出需续连或整问重建 session
同连接连发两问in-flight 锁或拒绝第二问

3.7 并发

  • 每用户每问:1× SpeechSynthesizer + 1× WSS
  • 全局:有界 TTS 连接池(如 32~64),超出排队
  • 禁止Spring 单例SpeechSynthesizer
  • WebSocketConnectionManager:增加sendBinary(connectionId, bytes)+ 与 Text 共用 outbound 队列

四、前端方案

4.1 状态机

IDLE → CONNECTED → AI_STREAMING → TEXT_DONE → VOICE_STREAMING → DONE ↓ content ↓ voiceFrame ↓ ↓ 追加播放队列
  • 文字:按序拼接content
  • 语音:按messageId+seq维护播放队列

4.2 播放(微信小程序)

方案做法适用
A. Base64 → 临时文件每句/每 N 帧攒成 WAV →wx.getFileSystemManager写 temp →InnerAudioContext.src改造小,延迟略高于 H5
B. 句子级 WAVsentence-end后拼帧写文件再播与 CosyVoice 分句对齐,推荐
C. 降级 URL仍收voiceChunk.voiceUrl兼容旧版

不建议小程序裸 PCM 逐帧直播(无 Web Audio,实现成本高)。

4.3 前端伪代码

consttextBuf={};constaudioQueue=[];// { messageId, seq, pcmChunks[] }letplaying=false;onMessage(msg){switch(msg.type){case'content':appendText(msg.messageId,msg.content);break;case'voiceFrame':enqueueFrame(msg);tryPlayNext();break;case'textComplete':markTextDone(msg.messageId);break;case'voiceComplete':case'complete':finishSession(msg.messageId);break;}}

4.4 与旧协议兼容

  • 检测首包:有voiceFrame走流式;仅有voiceChunk走 URL 队列
  • 版本号:连接时?voiceProtocol=2connected里带features: ["voiceStream"]

五、分阶段实施

阶段内容风险
P0SDK 升级 +CosyVoiceStreamingSessionPoC;服务端收帧落日志
P1voiceFrameBase64 推 WS;小程序句子级 temp 文件播放
P2去掉段级 OSS + 本地VoiceStreamingSegmentBuffer;complete 与 TTS 解耦
P3outbound 队列、有界连接池、in-flight 锁
P4可选 Binary 帧、H5 Web Audio 低延迟路径

六、和现有voiceChunk对比

现在voiceChunk+ OSS双向streamingCall
首包延迟整句合成 + 上传更低(帧级)
带宽客户端拉 OSSWS 直推(Base64 更大)
小程序InnerAudio + URL成熟需 temp 文件或句子 WAV
服务端简单WSS 长连接 + 队列 + 协议
历史回放段级 + merge仅 merge 一次即可

七、推荐结论

推荐路径LLM 文字协议不动 + CosyVoice 双向流式 +voiceFrame(句子边界拼 WAV)+ 结束 merge 一次 OSS + 文字结束立即complete+ 语音失败可降级无 voice。

  • 后端核心CosyVoiceStreamingSession+ 文本单线程 feeder + outbound 串行队列
  • 前端核心:按messageId/seq攒帧,按句写 temp WAV 播放
  • 兼容:保留voiceChunk作降级开关

若要落地 P0/P1,切Agent 模式可从VoiceSynthesisService+ImStreamingVoicePushSession改造起笔。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/3 6:22:50

2026 年 AI 开发网站教程,零代码快速搭建官网

2026 年 AI 开发网站教程,零代码快速搭建官网一、零代码建站到底有多简单“我不懂代码,但我需要给公司做个官网。”——这是无数中小企业主和创业者的真实处境。全国使用互联网开展营销推广的企业占比达 89.7%,但其中相当一部分人的技术能力几…

作者头像 李华
网站建设 2026/7/2 16:15:13

2026 进出口全流程科普,从资质办理到合规经营吴江实战案例

2026 进出口全流程科普:从资质办理到合规经营,吕鸿龙实战案例拆解外贸避坑指南 随着 RCEP 红利持续释放、出口退税无纸化全面落地,苏州吴江大量制造企业、跨境商家纷纷布局进出口业务。但多数外贸新手卡在资质办理、财税合规、政策运用三大环…

作者头像 李华
网站建设 2026/7/1 4:03:34

AI Agent安全新挑战:SkillSpector如何扫描技能漏洞与防范风险

你有没有遇到过这种情况:花了好几天时间,精心设计了一个AI Agent,让它能调用各种外部工具、处理复杂任务,结果刚上线没多久,就发现它可能被诱导去执行一些你从未预料到的操作?比如,一个原本用来…

作者头像 李华
网站建设 2026/7/1 4:02:33

2026年6月亲测!这家封箱机定制厂真靠谱

一、行业痛点分析 在工字封箱机定制厂家领域,存在着诸多核心技术挑战。数据表明,传统工字封箱机在面对复杂工况时,故障发生率高达30%,严重影响生产效率。同时,其对不同规格产品的适配性差,切换产品规格时&…

作者头像 李华
网站建设 2026/7/1 4:01:37

一文搞明白 hipBLAS:ROCm 里的 BLAS 加速核心

一文搞明白 hipBLAS:ROCm 里的 BLAS 加速核心 在 GPU 计算世界里,只要你碰到“矩阵乘法、向量加法、Transformer、CNN”,几乎都绕不开一个关键词:BLAS(Basic Linear Algebra Subprograms)。 在 NVIDIA CUDA…

作者头像 李华
网站建设 2026/7/1 4:01:25

快上车!掌握多尺度Mamba新方法,快人一步发文章

听说有人觉得transformer太卷了,想搞新的,不如看看mamba?当然,纯单尺度Mamba也是卷上加卷,我是说多尺度mamba这块,它是SSM子方向最成熟、产出最多、赛道最宽的选题了。当前的多尺度mamba有三大落地赛道&…

作者头像 李华