@voice-ping/cognitive-services-speech
Version:
VoicePing Cognitive Services Speech SDK for JavaScript forked from Microsoft
448 lines (446 loc) • 24.2 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
Object.defineProperty(exports, "__esModule", { value: true });
var Exports_1 = require("../common/Exports");
var Exports_2 = require("../sdk/Exports");
var Exports_3 = require("./Exports");
var SpeechConnectionMessage_Internal_1 = require("./SpeechConnectionMessage.Internal");
var SynthesisAdapterBase = /** @class */ (function () {
function SynthesisAdapterBase(authentication, connectionFactory, synthesizerConfig, speechSynthesizer, audioDestination) {
var _this = this;
this.speakOverride = undefined;
this.receiveMessageOverride = undefined;
this.connectImplOverride = undefined;
this.configConnectionOverride = undefined;
this.fetchConnectionOverride = undefined;
this.receiveMessage = function () {
return _this.fetchConnection().on(function (connection) {
return connection.read()
.onSuccessContinueWithPromise(function (message) {
if (_this.receiveMessageOverride !== undefined) {
return _this.receiveMessageOverride();
}
if (_this.privIsDisposed) {
// We're done.
return Exports_1.PromiseHelper.fromResult(undefined);
}
// indicates we are draining the queue and it came with no message;
if (!message) {
if (!_this.privSynthesisTurn.isSynthesizing) {
return Exports_1.PromiseHelper.fromResult(true);
}
else {
return _this.receiveMessage();
}
}
_this.privServiceHasSentMessage = true;
var connectionMessage = SpeechConnectionMessage_Internal_1.SpeechConnectionMessage.fromConnectionMessage(message);
if (connectionMessage.requestId.toLowerCase() === _this.privSynthesisTurn.requestId.toLowerCase()) {
switch (connectionMessage.path.toLowerCase()) {
case "turn.start":
_this.privSynthesisTurn.onServiceTurnStartResponse();
break;
case "response":
_this.privSynthesisTurn.onServiceResponseMessage(connectionMessage.textBody);
break;
case "audio":
if (_this.privSynthesisTurn.streamId.toLowerCase() === connectionMessage.streamId.toLowerCase()
&& !!connectionMessage.binaryBody) {
_this.privSynthesisTurn.onAudioChunkReceived(connectionMessage.binaryBody);
if (!!_this.privSpeechSynthesizer.synthesizing) {
try {
var audioWithHeader = SynthesisAdapterBase.addHeader(connectionMessage.binaryBody, _this.privSynthesisTurn.audioOutputFormat);
var ev = new Exports_2.SpeechSynthesisEventArgs(new Exports_2.SpeechSynthesisResult(_this.privSynthesisTurn.requestId, Exports_2.ResultReason.SynthesizingAudio, audioWithHeader));
_this.privSpeechSynthesizer.synthesizing(_this.privSpeechSynthesizer, ev);
}
catch (error) {
// Not going to let errors in the event handler
// trip things up.
}
}
if (_this.privSessionAudioDestination !== undefined) {
_this.privSessionAudioDestination.write(connectionMessage.binaryBody);
}
}
break;
case "audio.metadata":
var metadataList = Exports_3.SynthesisAudioMetadata.fromJSON(connectionMessage.textBody).Metadata;
for (var _i = 0, metadataList_1 = metadataList; _i < metadataList_1.length; _i++) {
var metadata = metadataList_1[_i];
if (metadata.Type.toLowerCase() === "WordBoundary".toLowerCase()) {
_this.privSynthesisTurn.onWordBoundaryEvent(metadata.Data.text.Text);
var ev = new Exports_2.SpeechSynthesisWordBoundaryEventArgs(metadata.Data.Offset, metadata.Data.text.Text, metadata.Data.text.Length, _this.privSynthesisTurn.currentTextOffset);
if (!!_this.privSpeechSynthesizer.wordBoundary) {
try {
_this.privSpeechSynthesizer.wordBoundary(_this.privSpeechSynthesizer, ev);
}
catch (error) {
// Not going to let errors in the event handler
// trip things up.
}
}
}
}
break;
case "turn.end":
_this.privSynthesisTurn.onServiceTurnEndResponse();
var result = void 0;
try {
result = new Exports_2.SpeechSynthesisResult(_this.privSynthesisTurn.requestId, Exports_2.ResultReason.SynthesizingAudioCompleted, _this.privSynthesisTurn.allReceivedAudioWithHeader);
if (!!_this.privSuccessCallback) {
_this.privSuccessCallback(result);
}
}
catch (error) {
if (!!_this.privErrorCallback) {
_this.privErrorCallback(error);
}
}
if (_this.privSpeechSynthesizer.synthesisCompleted) {
try {
_this.privSpeechSynthesizer.synthesisCompleted(_this.privSpeechSynthesizer, new Exports_2.SpeechSynthesisEventArgs(result));
}
catch (e) {
// Not going to let errors in the event handler
// trip things up.
}
}
break;
default:
if (!_this.processTypeSpecificMessages(connectionMessage)) {
// here are some messages that the derived class has not processed, dispatch them to connect class
if (!!_this.privServiceEvents) {
_this.serviceEvents.onEvent(new Exports_1.ServiceEvent(connectionMessage.path.toLowerCase(), connectionMessage.textBody));
}
}
}
}
return _this.receiveMessage();
});
}, function (error) {
});
};
this.sendSynthesisContext = function (connection) {
var synthesisContextJson = _this.synthesisContext.toJSON();
if (synthesisContextJson) {
return connection.send(new SpeechConnectionMessage_Internal_1.SpeechConnectionMessage(Exports_1.MessageType.Text, "synthesis.context", _this.privSynthesisTurn.requestId, "application/json", synthesisContextJson));
}
return Exports_1.PromiseHelper.fromResult(true);
};
this.sendSpeechServiceConfig = function (connection, SpeechServiceConfigJson) {
if (SpeechServiceConfigJson) {
return connection.send(new SpeechConnectionMessage_Internal_1.SpeechConnectionMessage(Exports_1.MessageType.Text, "speech.config", _this.privSynthesisTurn.requestId, "application/json", SpeechServiceConfigJson));
}
return Exports_1.PromiseHelper.fromResult(true);
};
this.sendSsmlMessage = function (connection, ssml, requestId) {
return connection.send(new SpeechConnectionMessage_Internal_1.SpeechConnectionMessage(Exports_1.MessageType.Text, "ssml", requestId, "application/ssml+xml", ssml));
};
this.fetchConnection = function () {
if (_this.fetchConnectionOverride !== undefined) {
return _this.fetchConnectionOverride();
}
return _this.configureConnection();
};
if (!authentication) {
throw new Exports_1.ArgumentNullError("authentication");
}
if (!connectionFactory) {
throw new Exports_1.ArgumentNullError("connectionFactory");
}
if (!synthesizerConfig) {
throw new Exports_1.ArgumentNullError("synthesizerConfig");
}
this.privAuthentication = authentication;
this.privConnectionFactory = connectionFactory;
this.privSynthesizerConfig = synthesizerConfig;
this.privIsDisposed = false;
this.privSpeechSynthesizer = speechSynthesizer;
this.privSessionAudioDestination = audioDestination;
this.privSynthesisTurn = new Exports_3.SynthesisTurn();
this.privConnectionEvents = new Exports_1.EventSource();
this.privServiceEvents = new Exports_1.EventSource();
this.privSynthesisContext = new Exports_3.SynthesisContext(this.privSpeechSynthesizer);
this.privAgentConfig = new Exports_3.AgentConfig();
this.connectionEvents.attach(function (connectionEvent) {
if (connectionEvent.name === "ConnectionClosedEvent") {
var connectionClosedEvent = connectionEvent;
_this.cancelSynthesisLocal(Exports_2.CancellationReason.Error, connectionClosedEvent.statusCode === 1007 ? Exports_2.CancellationErrorCode.BadRequestParameters : Exports_2.CancellationErrorCode.ConnectionFailure, connectionClosedEvent.reason + " websocket error code: " + connectionClosedEvent.statusCode);
}
});
}
Object.defineProperty(SynthesisAdapterBase.prototype, "synthesisContext", {
get: function () {
return this.privSynthesisContext;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SynthesisAdapterBase.prototype, "agentConfig", {
get: function () {
return this.privAgentConfig;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SynthesisAdapterBase.prototype, "connectionEvents", {
get: function () {
return this.privConnectionEvents;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SynthesisAdapterBase.prototype, "serviceEvents", {
get: function () {
return this.privServiceEvents;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SynthesisAdapterBase.prototype, "activityTemplate", {
get: function () { return this.privActivityTemplate; },
set: function (messagePayload) { this.privActivityTemplate = messagePayload; },
enumerable: true,
configurable: true
});
Object.defineProperty(SynthesisAdapterBase.prototype, "audioOutputFormat", {
set: function (format) {
this.privAudioOutputFormat = format;
this.privSynthesisTurn.audioOutputFormat = format;
if (this.privSessionAudioDestination !== undefined) {
this.privSessionAudioDestination.format = format;
}
if (this.synthesisContext !== undefined) {
this.synthesisContext.audioOutputFormat = format;
}
},
enumerable: true,
configurable: true
});
SynthesisAdapterBase.addHeader = function (audio, format) {
if (!format.hasHeader) {
return audio;
}
format.updateHeader(audio.byteLength);
var tmp = new Uint8Array(audio.byteLength + format.header.byteLength);
tmp.set(new Uint8Array(format.header), 0);
tmp.set(new Uint8Array(audio), format.header.byteLength);
return tmp.buffer;
};
SynthesisAdapterBase.prototype.isDisposed = function () {
return this.privIsDisposed;
};
SynthesisAdapterBase.prototype.dispose = function (reason) {
this.privIsDisposed = true;
if (this.privSessionAudioDestination !== undefined) {
this.privSessionAudioDestination.close();
}
if (this.privConnectionConfigurationPromise) {
this.privConnectionConfigurationPromise.onSuccessContinueWith(function (connection) {
connection.dispose(reason);
});
}
};
SynthesisAdapterBase.prototype.connect = function () {
this.connectImpl().result();
};
SynthesisAdapterBase.prototype.connectAsync = function (cb, err) {
this.connectImpl().continueWith(function (promiseResult) {
try {
if (promiseResult.isError) {
if (!!err) {
err(promiseResult.error);
}
}
else if (promiseResult.isCompleted) {
if (!!cb) {
cb();
}
}
}
catch (e) {
if (!!err) {
err(e);
}
}
});
};
SynthesisAdapterBase.prototype.sendNetworkMessage = function (path, payload, success, err) {
var _this = this;
var type = typeof payload === "string" ? Exports_1.MessageType.Text : Exports_1.MessageType.Binary;
var contentType = typeof payload === "string" ? "application/json" : "";
this.fetchConnection().on(function (connection) {
connection.send(new SpeechConnectionMessage_Internal_1.SpeechConnectionMessage(type, path, _this.privSynthesisTurn.requestId, contentType, payload)).on(function () {
if (!!success) {
success();
}
}, function (error) {
if (!!err) {
err(error);
}
});
}, function (error) {
if (!!err) {
err(error);
}
});
};
SynthesisAdapterBase.prototype.Speak = function (text, isSSML, requestId, successCallback, errorCallBack, audioDestination) {
var _this = this;
var ssml;
if (isSSML) {
ssml = text;
}
else {
ssml = this.privSpeechSynthesizer.buildSsml(text);
}
if (this.speakOverride !== undefined) {
return this.speakOverride(ssml, requestId, successCallback, errorCallBack);
}
this.privSuccessCallback = successCallback;
this.privErrorCallback = errorCallBack;
this.privSynthesisTurn.startNewSynthesis(requestId, text, isSSML, audioDestination);
return this.fetchConnection().continueWithPromise(function (connection) {
if (connection.isError) {
_this.cancelSynthesisLocal(Exports_2.CancellationReason.Error, Exports_2.CancellationErrorCode.ConnectionFailure, connection.error);
return Exports_1.PromiseHelper.fromError(connection.error);
}
return _this.sendSynthesisContext(connection.result).continueWithPromise(function (result) {
if (result.isError) {
_this.cancelSynthesisLocal(Exports_2.CancellationReason.Error, Exports_2.CancellationErrorCode.ConnectionFailure, result.error);
return Exports_1.PromiseHelper.fromError(result.error);
}
return _this.sendSsmlMessage(connection.result, ssml, requestId).continueWithPromise(function (result) {
if (result.isError) {
_this.cancelSynthesisLocal(Exports_2.CancellationReason.Error, Exports_2.CancellationErrorCode.ConnectionFailure, result.error);
return Exports_1.PromiseHelper.fromError(result.error);
}
var synthesisStartEventArgs = new Exports_2.SpeechSynthesisEventArgs(new Exports_2.SpeechSynthesisResult(requestId, Exports_2.ResultReason.SynthesizingAudioStarted));
if (!!_this.privSpeechSynthesizer.synthesisStarted) {
_this.privSpeechSynthesizer.synthesisStarted(_this.privSpeechSynthesizer, synthesisStartEventArgs);
}
var messageRetrievalPromise = _this.receiveMessage();
return Exports_1.PromiseHelper.fromResult(true);
});
});
});
};
// Cancels synthesis.
SynthesisAdapterBase.prototype.cancelSynthesis = function (requestId, cancellationReason, errorCode, error) {
var properties = new Exports_2.PropertyCollection();
properties.setProperty(Exports_3.CancellationErrorCodePropertyName, Exports_2.CancellationErrorCode[errorCode]);
var result = new Exports_2.SpeechSynthesisResult(requestId, Exports_2.ResultReason.Canceled, undefined, error, properties);
if (!!this.privSpeechSynthesizer.SynthesisCanceled) {
var cancelEvent = new Exports_2.SpeechSynthesisEventArgs(result);
try {
this.privSpeechSynthesizer.SynthesisCanceled(this.privSpeechSynthesizer, cancelEvent);
/* tslint:disable:no-empty */
}
catch (_a) { }
}
if (!!this.privSuccessCallback) {
try {
this.privSuccessCallback(result);
/* tslint:disable:no-empty */
}
catch (_b) { }
}
};
// Cancels synthesis.
SynthesisAdapterBase.prototype.cancelSynthesisLocal = function (cancellationReason, errorCode, error) {
if (!!this.privSynthesisTurn.isSynthesizing) {
this.privSynthesisTurn.onStopSynthesizing();
this.cancelSynthesis(this.privSynthesisTurn.requestId, cancellationReason, errorCode, error);
}
};
SynthesisAdapterBase.prototype.processTypeSpecificMessages = function (connectionMessage, successCallback, errorCallBack) {
return true;
};
// Establishes a websocket connection to the end point.
SynthesisAdapterBase.prototype.connectImpl = function (isUnAuthorized) {
var _this = this;
if (isUnAuthorized === void 0) { isUnAuthorized = false; }
if (this.connectImplOverride !== undefined) {
return this.connectImplOverride(isUnAuthorized);
}
if (this.privConnectionPromise) {
if (this.privConnectionPromise.result().isCompleted &&
(this.privConnectionPromise.result().isError
|| this.privConnectionPromise.result().result.state() === Exports_1.ConnectionState.Disconnected) &&
this.privServiceHasSentMessage === true) {
this.privConnectionId = null;
this.privConnectionPromise = null;
this.privServiceHasSentMessage = false;
return this.connectImpl();
}
else {
return this.privConnectionPromise;
}
}
this.privAuthFetchEventId = Exports_1.createNoDashGuid();
this.privConnectionId = Exports_1.createNoDashGuid();
this.privSynthesisTurn.onPreConnectionStart(this.privAuthFetchEventId, this.privConnectionId);
var authPromise = isUnAuthorized ? this.privAuthentication.fetchOnExpiry(this.privAuthFetchEventId) : this.privAuthentication.fetch(this.privAuthFetchEventId);
this.privConnectionPromise = authPromise
.continueWithPromise(function (result) {
if (result.isError) {
_this.privSynthesisTurn.onAuthCompleted(true, result.error);
throw new Error(result.error);
}
else {
_this.privSynthesisTurn.onAuthCompleted(false);
}
var connection = _this.privConnectionFactory.create(_this.privSynthesizerConfig, result.result, _this.privConnectionId);
// Attach to the underlying event. No need to hold onto the detach pointers as in the event the connection goes away,
// it'll stop sending events.
connection.events.attach(function (event) {
_this.connectionEvents.onEvent(event);
});
return connection.open().onSuccessContinueWithPromise(function (response) {
if (response.statusCode === 200) {
_this.privSynthesisTurn.onPreConnectionStart(_this.privAuthFetchEventId, _this.privConnectionId);
_this.privSynthesisTurn.onConnectionEstablishCompleted(response.statusCode);
return Exports_1.PromiseHelper.fromResult(connection);
}
else if (response.statusCode === 403 && !isUnAuthorized) {
return _this.connectImpl(true);
}
else {
_this.privSynthesisTurn.onConnectionEstablishCompleted(response.statusCode, response.reason);
return Exports_1.PromiseHelper.fromError("Unable to contact server. StatusCode: " + response.statusCode + ", " + _this.privSynthesizerConfig.parameters.getProperty(Exports_2.PropertyId.SpeechServiceConnection_Endpoint) + " Reason: " + response.reason);
}
});
});
return this.privConnectionPromise;
};
// Takes an established websocket connection to the endpoint and sends speech configuration information.
SynthesisAdapterBase.prototype.configureConnection = function () {
var _this = this;
if (this.configConnectionOverride !== undefined) {
return this.configConnectionOverride();
}
if (this.privConnectionConfigurationPromise) {
if (this.privConnectionConfigurationPromise.result().isCompleted &&
(this.privConnectionConfigurationPromise.result().isError
|| this.privConnectionConfigurationPromise.result().result.state() === Exports_1.ConnectionState.Disconnected)) {
this.privConnectionConfigurationPromise = null;
return this.configureConnection();
}
else {
return this.privConnectionConfigurationPromise;
}
}
this.privConnectionConfigurationPromise = this.connectImpl().onSuccessContinueWithPromise(function (connection) {
return _this.sendSpeechServiceConfig(connection, _this.privSynthesizerConfig.SpeechServiceConfig.serialize())
.onSuccessContinueWith(function (_) {
return connection;
});
});
return this.privConnectionConfigurationPromise;
};
SynthesisAdapterBase.telemetryDataEnabled = true;
return SynthesisAdapterBase;
}());
exports.SynthesisAdapterBase = SynthesisAdapterBase;
//# sourceMappingURL=SynthesisAdapterBase.js.map