在 Azure 语音服务的 REST 接口上送 SSML 给 zh-CN-XiaoxiaoNeural,版本是 2024-04-01,文本里写了 想留停顿,合成出来的音频两个分句之间几乎没有间隙。把时长改成 3s 仍然听不出差别,试过在 break 前后加空格也没有用。

一开始怀疑是「转义后的尖括号被服务端过滤,只剩正文」,查了一圈,方向不对。

真正麻烦的地方在于,几个原因的现象几乎一样。该声音在部分区域端点不支持 break 标签的毫秒时长。也可能是SSML 被 SDK 二次转义,标签当成普通文本读了出来。

少数情况下是输出格式用的是低码率 mp3,静音被编码器裁掉了。

先用最简 SSML 确认 break 是否生效

curl -X POST "https://eastasia.tts.speech.microsoft.com/cognitiveservices/v1" -H "Ocp-Apim-Subscription-Key: $KEY" -H "Content-Type: application/ssml+xml" -H "X-Microsoft-OutputFormat: riff-24khz-16bit-mono-pcm" --data-binary @ssml.xml -o out.wav

接着把输出改成无损 wav 排除编码器裁静音

ffprobe -v error -show_entries stream=codec_name,sample_rate out.wav

再往下用静音检测量出停顿长度

ffmpeg -i out.wav -af silencedetect=noise=-40dB:d=0.3 -f null -

等前面都确认过,再改用 prosody 的 rate 参数控制节奏再对比

curl -X POST "https://eastasia.tts.speech.microsoft.com/cognitiveservices/v1" -H "Ocp-Apim-Subscription-Key: $KEY" -H "Content-Type: application/ssml+xml" --data-binary @ssml2.xml -o out2.wav

改完先别撤,确认这几项。silencedetect 输出的静音区间长度接近设定的 800ms,两个版本合成的音频在波形上能看到明显间隙。

mp3 编码会裁掉首尾静音,用 break 调停顿一定要输出 wav 验证,只看播放效果容易把编码问题当成标签不生效。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189