@voice-ping/cognitive-services-speech
Version:
VoicePing Cognitive Services Speech SDK for JavaScript forked from Microsoft
191 lines (189 loc) • 7.18 kB
JavaScript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { createNoDashGuid, Deferred, Events, PromiseState } from "../common/Exports";
import { PullAudioOutputStreamImpl } from "../sdk/Audio/AudioOutputStream";
import { SynthesisAdapterBase } from "./SynthesisAdapterBase";
import { ConnectingToSynthesisServiceEvent, SynthesisStartedEvent, SynthesisTriggeredEvent, } from "./SynthesisEvents";
export class SynthesisTurn {
constructor() {
this.privIsDisposed = false;
this.privIsSynthesizing = false;
this.privIsSynthesisEnded = false;
this.privBytesReceived = 0;
this.privTextOffset = 0;
this.privNextSearchTextIndex = 0;
this.onPreConnectionStart = (authFetchEventId, connectionId) => {
this.privAuthFetchEventId = authFetchEventId;
this.onEvent(new ConnectingToSynthesisServiceEvent(this.privRequestId, this.privAuthFetchEventId));
};
this.onAuthCompleted = (isError, error) => {
if (isError) {
this.onComplete();
}
};
this.onConnectionEstablishCompleted = (statusCode, reason) => {
if (statusCode === 200) {
this.onEvent(new SynthesisStartedEvent(this.requestId, this.privAuthFetchEventId));
this.privBytesReceived = 0;
return;
}
else if (statusCode === 403) {
this.onComplete();
}
};
this.onServiceResponseMessage = (responseJson) => {
const response = JSON.parse(responseJson);
this.streamId = response.audio.streamId;
};
this.onServiceTurnEndResponse = () => {
this.privTurnDeferral.resolve(true);
this.onComplete();
};
this.onServiceTurnStartResponse = () => {
if (this.privTurnDeferral.state() === PromiseState.None) {
// What? How are we starting a turn with another not done?
this.privTurnDeferral.reject("Another turn started before current completed.");
}
this.privTurnDeferral = new Deferred();
};
this.dispose = (error) => {
if (!this.privIsDisposed) {
// we should have completed by now. If we did not its an unknown error.
this.privIsDisposed = true;
}
};
this.onEvent = (event) => {
Events.instance.onEvent(event);
};
this.onComplete = () => {
if (this.privIsSynthesizing) {
this.privIsSynthesizing = false;
this.privIsSynthesisEnded = true;
this.privAudioOutputStream.close();
if (this.privTurnAudioDestination !== undefined) {
this.privTurnAudioDestination.close();
this.privTurnAudioDestination = undefined;
}
}
};
this.privRequestId = createNoDashGuid();
this.privTurnDeferral = new Deferred();
// We're not in a turn, so resolve.
this.privTurnDeferral.resolve(true);
}
get requestId() {
return this.privRequestId;
}
get streamId() {
return this.privStreamId;
}
set streamId(value) {
this.privStreamId = value;
}
get audioOutputFormat() {
return this.privAudioOutputFormat;
}
set audioOutputFormat(format) {
this.privAudioOutputFormat = format;
}
get turnCompletionPromise() {
return this.privTurnDeferral.promise();
}
get isSynthesisEnded() {
return this.privIsSynthesisEnded;
}
get isSynthesizing() {
return this.privIsSynthesizing;
}
get currentTextOffset() {
return this.privTextOffset;
}
// The number of bytes received for current turn
get bytesReceived() {
return this.privBytesReceived;
}
get allReceivedAudio() {
if (!!this.privReceivedAudio) {
return this.privReceivedAudio;
}
if (!this.privIsSynthesisEnded) {
return null;
}
this.readAllAudioFromStream();
return this.allReceivedAudio;
}
get allReceivedAudioWithHeader() {
if (!!this.privReceivedAudioWithHeader) {
return this.privReceivedAudioWithHeader;
}
if (!this.privIsSynthesisEnded) {
return null;
}
if (this.audioOutputFormat.hasHeader) {
this.privReceivedAudioWithHeader = SynthesisAdapterBase.addHeader(this.allReceivedAudio, this.audioOutputFormat);
return this.allReceivedAudioWithHeader;
}
else {
return this.allReceivedAudio;
}
}
startNewSynthesis(requestId, rawText, isSSML, audioDestination) {
this.privIsSynthesisEnded = false;
this.privIsSynthesizing = true;
this.privRequestId = requestId;
this.privRawText = rawText;
this.privIsSSML = isSSML;
this.privAudioOutputStream = new PullAudioOutputStreamImpl();
this.privAudioOutputStream.format = this.privAudioOutputFormat;
this.privReceivedAudio = null;
this.privReceivedAudioWithHeader = null;
this.privBytesReceived = 0;
this.privTextOffset = 0;
this.privNextSearchTextIndex = 0;
if (audioDestination !== undefined) {
this.privTurnAudioDestination = audioDestination;
this.privTurnAudioDestination.format = this.privAudioOutputFormat;
}
this.onEvent(new SynthesisTriggeredEvent(this.requestId, undefined, audioDestination === undefined ? undefined : audioDestination.id()));
}
onAudioChunkReceived(data) {
if (this.isSynthesizing) {
this.privAudioOutputStream.write(data);
this.privBytesReceived += data.byteLength;
if (this.privTurnAudioDestination !== undefined) {
this.privTurnAudioDestination.write(data);
}
}
}
onWordBoundaryEvent(text) {
this.updateTextOffset(text);
}
onStopSynthesizing() {
this.onComplete();
}
updateTextOffset(text) {
if (this.privTextOffset >= 0) {
this.privTextOffset = this.privRawText.indexOf(text, this.privNextSearchTextIndex);
if (this.privTextOffset >= 0) {
this.privNextSearchTextIndex = this.privTextOffset + text.length;
}
if (this.privIsSSML) {
if (this.privRawText.indexOf("<", this.privTextOffset + 1) > this.privRawText.indexOf(">", this.privTextOffset + 1)) {
this.updateTextOffset(text);
}
}
}
}
readAllAudioFromStream() {
if (this.privIsSynthesisEnded) {
this.privReceivedAudio = new ArrayBuffer(this.bytesReceived);
try {
this.privAudioOutputStream.read(this.privReceivedAudio);
}
catch (e) {
this.privReceivedAudio = new ArrayBuffer(0);
}
}
}
}
//# sourceMappingURL=SynthesisTurn.js.map