What happened?
TTS used to work a few weeks ago, but now fails in the SDK while STT is still fine. The problem can be reproduced by running the sample at https://github.com/Azure-Samples/cognitive-services-speech-sdk/tree/master/samples/js/node.
settings.js:
export const subscriptionKey = "YourSubscriptionKey";
export const serviceEndpoint = "https://southeastasia.api.cognitive.microsoft.com"; // e.g., "https://westus.api.cognitive.microsoft.com"
export const serviceRegion = "southeastasia"; // e.g., "westus"
export const language = "en-US";
// Replace with the full path to a wav file you want to recognize or overwrite.
export const filename = "YourAudioFile.wav"; // 16000 Hz, Mono
However, the REST version works.
curl --location --request POST "https://southeastasia.tts.speech.microsoft.com/cognitiveservices/v1" \
--header "Ocp-Apim-Subscription-Key: %SPEECH_KEY%"" \
--header "Content-Type: application/ssml+xml" \
--header "X-Microsoft-OutputFormat: audio-16khz-128kbitrate-mono-mp3" \
--header "User-Agent: curl" \
--data-raw "<speak version='1.0' xml:lang='en-US'><voice xml:lang='en-US' xml:gender='Female' name='en-us-Ava:DragonHDLatestNeural'>hello</voice></speak>" --output output.mp3
The error seems to be first caught by this.privWebsocketClient.onerror in WebsocketMessageAdapter.js. If I do WebsocketMessageAdapter.forceNpmWebSocket = true; before the connection, TTS seems to work.
WebsocketMessageAdapter.js:
open() {
if (this.privConnectionState === Exports_js_1.ConnectionState.Disconnected) {
return Promise.reject(`Cannot open a connection that is in ${this.privConnectionState} state`);
}
if (this.privConnectionEstablishDeferral) {
return this.privConnectionEstablishDeferral.promise;
}
this.privConnectionEstablishDeferral = new Exports_js_1.Deferred();
this.privCertificateValidatedDeferral = new Exports_js_1.Deferred();
this.privConnectionState = Exports_js_1.ConnectionState.Connecting;
try {
if (typeof WebSocket !== "undefined" && !WebsocketMessageAdapter.forceNpmWebSocket) {
// Browser handles cert checks.
this.privCertificateValidatedDeferral.resolve();
this.privWebsocketClient = new WebSocket(this.privUri);
}
else {
// Workaround for https://github.com/microsoft/cognitive-services-speech-sdk-js/issues/465
// Which is root caused by https://github.com/TooTallNate/node-agent-base/issues/61
const uri = new URL(this.privUri);
let protocol = uri.protocol;
if (protocol?.toLocaleLowerCase() === "wss:") {
protocol = "https:";
}
else if (protocol?.toLocaleLowerCase() === "ws:") {
protocol = "http:";
}
const options = { headers: this.privHeaders, perMessageDeflate: this.privEnableCompression, followRedirects: protocol.toLocaleLowerCase() === "https:" };
// The ocsp library will handle validation for us and fail the connection if needed.
this.privCertificateValidatedDeferral.resolve();
options.agent = this.getAgent();
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
options.agent.protocol = protocol;
this.privWebsocketClient = new ws_1.default(this.privUri, options);
this.privWebsocketClient.on("redirect", (redirectUrl) => {
const event = new Exports_js_1.ConnectionRedirectEvent(this.privConnectionId, redirectUrl, this.privUri, `Getting redirect URL from endpoint ${this.privUri} with redirect URL '${redirectUrl}'`);
Exports_js_1.Events.instance.onEvent(event);
});
}
this.privWebsocketClient.binaryType = "arraybuffer";
this.privReceivingMessageQueue = new Exports_js_1.Queue();
this.privDisconnectDeferral = new Exports_js_1.Deferred();
this.privSendMessageQueue = new Exports_js_1.Queue();
this.processSendQueue().catch((reason) => {
Exports_js_1.Events.instance.onEvent(new Exports_js_1.BackgroundEvent(reason));
});
}
catch (error) {
this.privConnectionEstablishDeferral.resolve(new Exports_js_1.ConnectionOpenResponse(500, error));
return this.privConnectionEstablishDeferral.promise;
}
this.onEvent(new Exports_js_1.ConnectionStartEvent(this.privConnectionId, this.privUri));
this.privWebsocketClient.onopen = () => {
this.privCertificateValidatedDeferral.promise.then(() => {
this.privConnectionState = Exports_js_1.ConnectionState.Connected;
this.onEvent(new Exports_js_1.ConnectionEstablishedEvent(this.privConnectionId));
this.privConnectionEstablishDeferral.resolve(new Exports_js_1.ConnectionOpenResponse(200, ""));
}, (error) => {
this.privConnectionEstablishDeferral.reject(error);
});
};
this.privWebsocketClient.onerror = (e) => {
this.onEvent(new Exports_js_1.ConnectionErrorEvent(this.privConnectionId, e.message, e.type));
this.privLastErrorReceived = e.message;
};
Version:
1.48.0, 1.47.0
Platform:
Node v25.1.0
docker node:lts-alpine3.23, Windows 10
Version
1.48.0 (Latest, Default)
What browser/platform are you seeing the problem on?
Node
Relevant log output
Now synthesizing to: YourAudioFile.wav
Type some text that you want to speak...
> a
(cancel) Reason: Error: Unable to contact server. StatusCode: 1006,
https://southeastasia.api.cognitive.microsoft.com/tts/cognitiveservices/websocket/v1 Reason:
What happened?
TTS used to work a few weeks ago, but now fails in the SDK while STT is still fine. The problem can be reproduced by running the sample at https://github.com/Azure-Samples/cognitive-services-speech-sdk/tree/master/samples/js/node.
settings.js:
However, the REST version works.
The error seems to be first caught by
this.privWebsocketClient.onerrorinWebsocketMessageAdapter.js. If I doWebsocketMessageAdapter.forceNpmWebSocket = true;before the connection, TTS seems to work.WebsocketMessageAdapter.js:
Version:
1.48.0, 1.47.0
Platform:
Node v25.1.0
docker node:lts-alpine3.23, Windows 10
Version
1.48.0 (Latest, Default)
What browser/platform are you seeing the problem on?
Node
Relevant log output
Now synthesizing to: YourAudioFile.wav Type some text that you want to speak... > a (cancel) Reason: Error: Unable to contact server. StatusCode: 1006, https://southeastasia.api.cognitive.microsoft.com/tts/cognitiveservices/websocket/v1 Reason: