@voice-ping/cognitive-services-speech
Version:
VoicePing Cognitive Services Speech SDK for JavaScript forked from Microsoft
424 lines (422 loc) • 19.8 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
// Multi-device Conversation is a Preview feature.
Object.defineProperty(exports, "__esModule", { value: true });
var Exports_1 = require("../../common.speech/Exports");
var Contracts_1 = require("../Contracts");
var Exports_2 = require("../Exports");
var Conversation_1 = require("./Conversation");
var Exports_3 = require("./Exports");
var SpeechState;
(function (SpeechState) {
SpeechState[SpeechState["Inactive"] = 0] = "Inactive";
SpeechState[SpeechState["Connecting"] = 1] = "Connecting";
SpeechState[SpeechState["Connected"] = 2] = "Connected";
})(SpeechState = exports.SpeechState || (exports.SpeechState = {}));
/***
* Join, leave or connect to a conversation.
*/
var ConversationTranslator = /** @class */ (function () {
function ConversationTranslator(audioConfig) {
var _this = this;
this.privIsDisposed = false;
this.privIsSpeaking = false;
this.privSpeechState = SpeechState.Inactive;
this.privErrors = Exports_1.ConversationConnectionConfig.restErrors;
this.privPlaceholderKey = "abcdefghijklmnopqrstuvwxyz012345";
this.privPlaceholderRegion = "westus";
/** Recognizer callbacks */
this.onSpeechConnected = function (e) {
_this.privSpeechState = SpeechState.Connected;
};
this.onSpeechDisconnected = function (e) {
_this.privSpeechState = SpeechState.Inactive;
_this.cancelSpeech();
};
this.onSpeechRecognized = function (r, e) {
// TODO: add support for getting recognitions from here if own speech
var _a;
// if there is an error connecting to the conversation service from the speech service the error will be returned in the ErrorDetails field.
if ((_a = e.result) === null || _a === void 0 ? void 0 : _a.errorDetails) {
_this.cancelSpeech();
// TODO: format the error message contained in 'errorDetails'
_this.fireCancelEvent(e.result.errorDetails);
}
};
this.onSpeechRecognizing = function (r, e) {
// TODO: add support for getting recognitions from here if own speech
};
this.onSpeechCanceled = function (r, e) {
if (_this.privSpeechState !== SpeechState.Inactive) {
try {
_this.cancelSpeech();
}
catch (error) {
_this.privSpeechState = SpeechState.Inactive;
}
}
};
this.onSpeechSessionStarted = function (r, e) {
_this.privSpeechState = SpeechState.Connected;
};
this.onSpeechSessionStopped = function (r, e) {
_this.privSpeechState = SpeechState.Inactive;
};
this.privProperties = new Exports_2.PropertyCollection();
this.privAudioConfig = audioConfig;
}
Object.defineProperty(ConversationTranslator.prototype, "properties", {
get: function () {
return this.privProperties;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ConversationTranslator.prototype, "speechRecognitionLanguage", {
get: function () {
return this.privSpeechRecognitionLanguage;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ConversationTranslator.prototype, "participants", {
get: function () {
var _a;
return (_a = this.privConversation) === null || _a === void 0 ? void 0 : _a.participants;
},
enumerable: true,
configurable: true
});
ConversationTranslator.prototype.joinConversationAsync = function (conversation, nickname, param1, param2, param3) {
var _this = this;
try {
if (typeof conversation === "string") {
Contracts_1.Contracts.throwIfNullOrUndefined(conversation, this.privErrors.invalidArgs.replace("{arg}", "conversation id"));
Contracts_1.Contracts.throwIfNullOrWhitespace(nickname, this.privErrors.invalidArgs.replace("{arg}", "nickname"));
if (!!this.privConversation) {
this.handleError(new Error(this.privErrors.permissionDeniedStart), param3);
}
var lang = param1;
if (lang === undefined || lang === null || lang === "") {
lang = Exports_1.ConversationConnectionConfig.defaultLanguageCode;
}
// create a placecholder config
this.privSpeechTranslationConfig = Exports_2.SpeechTranslationConfig.fromSubscription(this.privPlaceholderKey, this.privPlaceholderRegion);
this.privSpeechTranslationConfig.setProfanity(Exports_2.ProfanityOption.Masked);
this.privSpeechTranslationConfig.addTargetLanguage(lang);
this.privSpeechTranslationConfig.setProperty(Exports_2.PropertyId[Exports_2.PropertyId.SpeechServiceConnection_RecoLanguage], lang);
this.privSpeechTranslationConfig.setProperty(Exports_2.PropertyId[Exports_2.PropertyId.ConversationTranslator_Name], nickname);
var endpoint = this.privProperties.getProperty(Exports_2.PropertyId.ConversationTranslator_Host);
if (endpoint) {
this.privSpeechTranslationConfig.setProperty(Exports_2.PropertyId[Exports_2.PropertyId.ConversationTranslator_Host], endpoint);
}
var speechEndpointHost = this.privProperties.getProperty(Exports_2.PropertyId.SpeechServiceConnection_Host);
if (speechEndpointHost) {
this.privSpeechTranslationConfig.setProperty(Exports_2.PropertyId[Exports_2.PropertyId.SpeechServiceConnection_Host], speechEndpointHost);
}
// join the conversation
this.privConversation = new Conversation_1.ConversationImpl(this.privSpeechTranslationConfig);
this.privConversation.conversationTranslator = this;
this.privConversation.joinConversationAsync(conversation, nickname, lang, (function (result) {
if (!result) {
_this.handleError(new Error(_this.privErrors.permissionDeniedConnect), param3);
}
_this.privSpeechTranslationConfig.authorizationToken = result;
// connect to the ws
_this.privConversation.startConversationAsync((function () {
_this.handleCallback(param2, param3);
}), (function (error) {
_this.handleError(error, param3);
}));
}), (function (error) {
_this.handleError(error, param3);
}));
}
else if (typeof conversation === "object") {
Contracts_1.Contracts.throwIfNullOrUndefined(conversation, this.privErrors.invalidArgs.replace("{arg}", "conversation id"));
Contracts_1.Contracts.throwIfNullOrWhitespace(nickname, this.privErrors.invalidArgs.replace("{arg}", "nickname"));
// save the nickname
this.privProperties.setProperty(Exports_2.PropertyId.ConversationTranslator_Name, nickname);
// ref the conversation object
this.privConversation = conversation;
// ref the conversation translator object
this.privConversation.conversationTranslator = this;
Contracts_1.Contracts.throwIfNullOrUndefined(this.privConversation, this.privErrors.permissionDeniedConnect);
Contracts_1.Contracts.throwIfNullOrUndefined(this.privConversation.room.token, this.privErrors.permissionDeniedConnect);
this.privSpeechTranslationConfig = conversation.config;
this.handleCallback(param1, param2);
}
else {
this.handleError(new Error(this.privErrors.invalidArgs.replace("{arg}", "invalid conversation type")), param2);
}
}
catch (error) {
this.handleError(error, typeof param1 === "string" ? param3 : param2);
}
};
/**
* Leave the conversation
* @param cb
* @param err
*/
ConversationTranslator.prototype.leaveConversationAsync = function (cb, err) {
var _this = this;
try {
// stop the speech websocket
this.cancelSpeech();
// stop the websocket
this.privConversation.endConversationAsync((function () {
// https delete request
_this.privConversation.deleteConversationAsync((function () {
_this.handleCallback(cb, err);
_this.dispose();
}), (function (error) {
_this.handleError(error, err);
}));
}), (function (error) {
_this.handleError(error, err);
}));
}
catch (error) {
this.handleError(error, err);
}
};
/**
* Send a text message
* @param message
* @param cb
* @param err
*/
ConversationTranslator.prototype.sendTextMessageAsync = function (message, cb, err) {
var _a;
try {
Contracts_1.Contracts.throwIfNullOrUndefined(this.privConversation, this.privErrors.permissionDeniedSend);
Contracts_1.Contracts.throwIfNullOrWhitespace(message, this.privErrors.invalidArgs.replace("{arg}", message));
(_a = this.privConversation) === null || _a === void 0 ? void 0 : _a.sendTextMessageAsync(message, cb, err);
}
catch (error) {
this.handleError(error, err);
}
};
/**
* Start speaking
* @param cb
* @param err
*/
ConversationTranslator.prototype.startTranscribingAsync = function (cb, err) {
var _this = this;
try {
Contracts_1.Contracts.throwIfNullOrUndefined(this.privConversation, this.privErrors.permissionDeniedSend);
Contracts_1.Contracts.throwIfNullOrUndefined(this.privConversation.room.token, this.privErrors.permissionDeniedConnect);
if (!this.canSpeak) {
this.handleError(new Error(this.privErrors.permissionDeniedSend), err);
}
if (this.privTranslationRecognizer === undefined) {
this.connectTranslatorRecognizer((function () {
_this.startContinuousRecognition((function () {
_this.privIsSpeaking = true;
_this.handleCallback(cb, err);
}), (function (error) {
_this.privIsSpeaking = false;
// this.fireCancelEvent(error);
_this.cancelSpeech();
_this.handleError(error, err);
}));
}), (function (error) {
_this.handleError(error, err);
}));
}
else {
this.startContinuousRecognition((function () {
_this.privIsSpeaking = true;
_this.handleCallback(cb, err);
}), (function (error) {
_this.privIsSpeaking = false;
// this.fireCancelEvent(error);
_this.cancelSpeech();
_this.handleError(error, err);
}));
}
}
catch (error) {
this.handleError(error, err);
this.cancelSpeech();
}
};
/**
* Stop speaking
* @param cb
* @param err
*/
ConversationTranslator.prototype.stopTranscribingAsync = function (cb, err) {
var _this = this;
var _a;
try {
if (!this.privIsSpeaking) {
// stop speech
this.cancelSpeech();
this.handleCallback(cb, err);
return;
}
// stop the recognition but leave the websocket open
this.privIsSpeaking = false;
(_a = this.privTranslationRecognizer) === null || _a === void 0 ? void 0 : _a.stopContinuousRecognitionAsync(function () {
_this.handleCallback(cb, err);
}, function (error) {
_this.handleError(error, err);
_this.cancelSpeech();
});
}
catch (error) {
this.handleError(error, err);
this.cancelSpeech();
}
};
ConversationTranslator.prototype.isDisposed = function () {
return this.privIsDisposed;
};
ConversationTranslator.prototype.dispose = function (reason) {
var _a, _b;
if (this.isDisposed && !this.privIsSpeaking) {
return;
}
this.cancelSpeech();
this.privIsDisposed = true;
(_a = this.privSpeechTranslationConfig) === null || _a === void 0 ? void 0 : _a.close();
this.privSpeechRecognitionLanguage = undefined;
this.privProperties = undefined;
this.privAudioConfig = undefined;
this.privSpeechTranslationConfig = undefined;
(_b = this.privConversation) === null || _b === void 0 ? void 0 : _b.dispose();
this.privConversation = undefined;
};
/**
* Connect to the speech translation recognizer.
* Currently there is no language validation performed before sending the SpeechLanguage code to the service.
* If it's an invalid language the raw error will be: 'Error during WebSocket handshake: Unexpected response code: 400'
* e.g. pass in 'fr' instead of 'fr-FR', or a text-only language 'cy'
* @param cb
* @param err
*/
ConversationTranslator.prototype.connectTranslatorRecognizer = function (cb, err) {
try {
if (this.privAudioConfig === undefined) {
this.privAudioConfig = Exports_2.AudioConfig.fromDefaultMicrophoneInput();
}
// clear the temp subscription key if it's a participant joining
if (this.privSpeechTranslationConfig.getProperty(Exports_2.PropertyId[Exports_2.PropertyId.SpeechServiceConnection_Key])
=== this.privPlaceholderKey) {
this.privSpeechTranslationConfig.setProperty(Exports_2.PropertyId[Exports_2.PropertyId.SpeechServiceConnection_Key], "");
}
// TODO
var token = encodeURIComponent(this.privConversation.room.token);
var endpointHost = this.privSpeechTranslationConfig.getProperty(Exports_2.PropertyId[Exports_2.PropertyId.SpeechServiceConnection_Host], Exports_1.ConversationConnectionConfig.speechHost);
endpointHost = endpointHost.replace("{region}", this.privConversation.room.cognitiveSpeechRegion);
var url = "wss://" + endpointHost + Exports_1.ConversationConnectionConfig.speechPath + "?" + Exports_1.ConversationConnectionConfig.configParams.token + "=" + token;
this.privSpeechTranslationConfig.setProperty(Exports_2.PropertyId[Exports_2.PropertyId.SpeechServiceConnection_Endpoint], url);
this.privTranslationRecognizer = new Exports_2.TranslationRecognizer(this.privSpeechTranslationConfig, this.privAudioConfig);
this.privTranslationRecognizerConnection = Exports_2.Connection.fromRecognizer(this.privTranslationRecognizer);
this.privTranslationRecognizerConnection.connected = this.onSpeechConnected;
this.privTranslationRecognizerConnection.disconnected = this.onSpeechDisconnected;
this.privTranslationRecognizer.recognized = this.onSpeechRecognized;
this.privTranslationRecognizer.recognizing = this.onSpeechRecognizing;
this.privTranslationRecognizer.canceled = this.onSpeechCanceled;
this.privTranslationRecognizer.sessionStarted = this.onSpeechSessionStarted;
this.privTranslationRecognizer.sessionStopped = this.onSpeechSessionStopped;
this.handleCallback(cb, err);
}
catch (error) {
this.handleError(error, err);
this.cancelSpeech();
// this.fireCancelEvent(error); ?
}
};
/**
* Handle the start speaking request
* @param cb
* @param err
*/
ConversationTranslator.prototype.startContinuousRecognition = function (cb, err) {
this.privTranslationRecognizer.startContinuousRecognitionAsync(cb, err);
};
/**
* Fire a cancel event
* @param error
*/
ConversationTranslator.prototype.fireCancelEvent = function (error) {
var _a, _b, _c, _d, _e, _f, _g;
try {
if (!!this.canceled) {
var cancelEvent = new Exports_3.ConversationTranslationCanceledEventArgs((_b = (_a = error) === null || _a === void 0 ? void 0 : _a.reason, (_b !== null && _b !== void 0 ? _b : Exports_2.CancellationReason.Error)), (_d = (_c = error) === null || _c === void 0 ? void 0 : _c.errorDetails, (_d !== null && _d !== void 0 ? _d : error)), (_f = (_e = error) === null || _e === void 0 ? void 0 : _e.errorCode, (_f !== null && _f !== void 0 ? _f : Exports_2.CancellationErrorCode.RuntimeError)), undefined, (_g = error) === null || _g === void 0 ? void 0 : _g.sessionId);
this.canceled(this, cancelEvent);
}
}
catch (e) {
//
}
};
/**
* Cancel the speech websocket
*/
ConversationTranslator.prototype.cancelSpeech = function () {
var _a, _b;
try {
this.privIsSpeaking = false;
(_a = this.privTranslationRecognizer) === null || _a === void 0 ? void 0 : _a.stopContinuousRecognitionAsync();
(_b = this.privTranslationRecognizerConnection) === null || _b === void 0 ? void 0 : _b.closeConnection();
this.privTranslationRecognizerConnection = undefined;
this.privTranslationRecognizer = undefined;
this.privSpeechState = SpeechState.Inactive;
}
catch (e) {
// ignore the error
}
};
Object.defineProperty(ConversationTranslator.prototype, "canSpeak", {
get: function () {
// is there a Conversation websocket available
if (!this.privConversation.isConnected) {
return false;
}
// is the user already speaking
if (this.privIsSpeaking || this.privSpeechState === SpeechState.Connected || this.privSpeechState === SpeechState.Connecting) {
return false;
}
// is the user muted
if (this.privConversation.isMutedByHost) {
return false;
}
return true;
},
enumerable: true,
configurable: true
});
ConversationTranslator.prototype.handleCallback = function (cb, err) {
if (!!cb) {
try {
cb();
}
catch (e) {
if (!!err) {
err(e);
}
}
cb = undefined;
}
};
ConversationTranslator.prototype.handleError = function (error, err) {
if (!!err) {
if (error instanceof Error) {
var typedError = error;
err(typedError.name + ": " + typedError.message);
}
else {
err(error);
}
}
};
return ConversationTranslator;
}());
exports.ConversationTranslator = ConversationTranslator;
//# sourceMappingURL=ConversationTranslator.js.map