Azure TTS WebSocket流式传输报错:Input stream cannot be null 求助
Azure TTS WebSocket流式文本转语音:"Input stream cannot be null"错误调试
错误输出
WebSocket connection established --------------open done------------------ Received message: X-RequestId:13604750-2bxd-42a2-b523-cdesadas3d47 Content-Type:application/json; charset=utf-8 Path:turn.start { "context": { "serviceTag": "9a23ce3549axdf7ddfg1d42317bcx5210" } } WebSocket connection closed with code 1007. Reason: Input stream cannot be null
核心实现代码
import WebSocket from 'ws'; import axios from 'axios'; import crypto from 'crypto'; async function streamTextToSpeech(textStream) { const accessToken = await getAccessToken(); const ws = new WebSocket( `wss://${region}.tts.speech.microsoft.com/cognitiveservices/websocket/v2?Authorization=Bearer ${accessToken}` ); ws.on('open', () => { // 发送配置消息 const configMessage = { context: { synthesis: { audio: { metadataOptions: { sentenceBoundaryEnabled: 'false', wordBoundaryEnabled: 'false' }, outputFormat: 'audio-24khz-48kbitrate-mono-mp3' }, language: { autoDetection: false }, voice: { languageId: 'en-US', name: 'en-US-JennyNeural' } } } }; const configMessageString = `Content-Type:application/json\r\nPath:speech.config\r\n\r\n${JSON.stringify(configMessage)}`; ws.send(configMessageString); // 报错位置 const initialSsml = `<speak version='1.0' xml:lang='en-US'><voice name='en-US-JennyNeural'>Initializing speech synthesis.</voice></speak>`; const initialMessage = `Path:ssml\r\nX-RequestId:${crypto.randomUUID()}\r\nContent-Type:application/ssml+xml\r\n\r\n${initialSsml}`; ws.send(initialMessage); }); // 错误处理及消息处理代码... }
环境信息
- Node.js: 14.17.0
- ws: 8.2.3
- axios: 0.24.0
- Azure Cognitive Services API: v2
已尝试排查步骤
- 验证WebSocket连接参数与认证信息
- 对照Azure文档核对SSML格式
- 确认访问令牌有效且格式正确
- 尝试查找Python SDK源码但未找到
疑问
- 发送初始SSML消息时“Input stream cannot be null”错误的原因是什么?
- 针对Azure TTS API的WebSocket消息格式是否正确?
- 使用WebSocket API时SSML格式有哪些特定要求?
问题分析与解决方案
1. "Input stream cannot be null"错误原因
核心原因是消息时序违规:发送speech.config后未等待服务端返回turn.start确认,就直接发送SSML消息。Azure TTS WebSocket协议明确要求,必须在收到服务端的turn.start响应后,才能开始发送SSML内容,否则服务端会判定输入流未完成初始化,抛出该错误。
2. WebSocket消息格式修正
当前实现存在两个关键问题:
- 时序错误:需监听服务端
turn.start消息后再发送SSML - 消息头缺失:SSML消息必须携带
Content-Length字段,服务端依赖该字段解析内容
修正后的核心逻辑:
ws.on('open', () => { // 发送配置消息逻辑不变 const configMessage = { /* ... */ }; const configMessageString = `Content-Type:application/json\r\nPath:speech.config\r\n\r\n${JSON.stringify(configMessage)}`; ws.send(configMessageString); }); // 新增消息监听,等待turn.start后发送SSML ws.on('message', (data) => { const messageStr = data.toString(); if (messageStr.includes('Path:turn.start')) { const initialSsml = `<speak version="1.0" xml:lang="en-US"><voice name="en-US-JennyNeural">Initializing speech synthesis.</voice></speak>`; const contentLength = Buffer.byteLength(initialSsml, 'utf8'); const initialMessage = `Path:ssml\r\nX-RequestId:${crypto.randomUUID()}\r\nContent-Type:application/ssml+xml\r\nContent-Length:${contentLength}\r\n\r\n${initialSsml}`; ws.send(initialMessage); } });
3. WebSocket API的SSML格式要求
- 严格遵循XML规范:属性值必须使用双引号(避免单引号,部分解析器会触发语法错误)
<speak>标签必须同时指定version和xml:lang属性,且xml:lang需与语音配置的languageId完全一致<voice>标签的name必须是Azure官方支持的神经语音名称,可通过Azure门户或产品文档确认有效列表- 禁止包含未闭合标签、非法XML字符(如未转义的
&、<),否则服务端会直接断开连接
内容的提问来源于stack exchange,提问作者Darius Andrei Rozemberg
相关产品推荐
相关产品推荐

