{"version":3,"sources":["src/common.speech/SynthesisTurn.ts"],"names":[],"mappings":"AAGA,OAAO,EAGK,iBAAiB,EACzB,OAAO,EAEV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAGvE,OAAO,EAEH,oBAAoB,EAGvB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,yBAAyB;IACtC,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,yBAAyB,CAAC;IACnC,KAAK,EAAE,uBAAuB,CAAC;CAClC;AAED,qBAAa,aAAa;IAEtB,IAAW,SAAS,IAAI,MAAM,CAE7B;IAED,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAED,IAAW,QAAQ,CAAC,KAAK,EAAE,MAAM,EAEhC;IAED,IAAW,iBAAiB,IAAI,qBAAqB,CAEpD;IAED,IAAW,iBAAiB,CAAC,MAAM,EAAE,qBAAqB,EAEzD;IAED,IAAW,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAEnD;IAED,IAAW,gBAAgB,IAAI,OAAO,CAErC;IAED,IAAW,cAAc,IAAI,OAAO,CAEnC;IAED,IAAW,iBAAiB,IAAI,MAAM,CAErC;IAGD,IAAW,aAAa,IAAI,MAAM,CAEjC;IAED,IAAW,gBAAgB,IAAI,WAAW,CASzC;IAED,IAAW,0BAA0B,IAAI,WAAW,CAanD;IACD,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,oBAAoB,CAAkB;IAC9C,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,qBAAqB,CAAwB;IACrD,OAAO,CAAC,qBAAqB,CAA4B;IACzD,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,2BAA2B,CAAc;IACjD,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,uBAAuB,CAAa;IAC5C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,wBAAwB,CAAoB;;IAU7C,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,EAAE,iBAAiB,GAAG,IAAI;IAoBlH,oBAAoB,2DAG1B;IAEM,eAAe,6CAIrB;IAEM,8BAA8B,gDAQpC;IAEM,wBAAwB,iCAG9B;IAEM,wBAAwB,aAG9B;IAEM,0BAA0B,aAOhC;IAEM,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAU7C,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIvC,OAAO,2BAKb;IAEM,kBAAkB,IAAI,IAAI;IAIjC,SAAS,CAAC,OAAO,wCAEhB;IAED,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,UAAU,CAUjB;IAED,OAAO,CAAC,sBAAsB;CAUjC","file":"SynthesisTurn.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nimport {\n    createNoDashGuid,\n    Deferred,\n    Events, IAudioDestination,\n    Promise,\n    PromiseState\n} from \"../common/Exports\";\nimport { AudioOutputFormatImpl } from \"../sdk/Audio/AudioOutputFormat\";\nimport { PullAudioOutputStreamImpl } from \"../sdk/Audio/AudioOutputStream\";\nimport {SynthesisAdapterBase} from \"./SynthesisAdapterBase\";\nimport {\n    ConnectingToSynthesisServiceEvent,\n    SpeechSynthesisEvent,\n    SynthesisStartedEvent,\n    SynthesisTriggeredEvent,\n} from \"./SynthesisEvents\";\n\nexport interface ISynthesisResponseContext {\n    serviceTag: string;\n}\n\nexport interface ISynthesisResponseAudio {\n    type: string;\n    streamId: string;\n}\n\nexport interface ISynthesisResponse {\n    context: ISynthesisResponseContext;\n    audio: ISynthesisResponseAudio;\n}\n\nexport class SynthesisTurn {\n\n    public get requestId(): string {\n        return this.privRequestId;\n    }\n\n    public get streamId(): string {\n        return this.privStreamId;\n    }\n\n    public set streamId(value: string) {\n        this.privStreamId = value;\n    }\n\n    public get audioOutputFormat(): AudioOutputFormatImpl {\n        return this.privAudioOutputFormat;\n    }\n\n    public set audioOutputFormat(format: AudioOutputFormatImpl) {\n        this.privAudioOutputFormat = format;\n    }\n\n    public get turnCompletionPromise(): Promise<boolean> {\n        return this.privTurnDeferral.promise();\n    }\n\n    public get isSynthesisEnded(): boolean {\n        return this.privIsSynthesisEnded;\n    }\n\n    public get isSynthesizing(): boolean {\n        return this.privIsSynthesizing;\n    }\n\n    public get currentTextOffset(): number {\n        return this.privTextOffset;\n    }\n\n    // The number of bytes received for current turn\n    public get bytesReceived(): number {\n        return this.privBytesReceived;\n    }\n\n    public get allReceivedAudio(): ArrayBuffer {\n        if (!!this.privReceivedAudio) {\n            return this.privReceivedAudio;\n        }\n        if (!this.privIsSynthesisEnded) {\n            return null;\n        }\n        this.readAllAudioFromStream();\n        return this.allReceivedAudio;\n    }\n\n    public get allReceivedAudioWithHeader(): ArrayBuffer {\n        if (!!this.privReceivedAudioWithHeader) {\n            return this.privReceivedAudioWithHeader;\n        }\n        if (!this.privIsSynthesisEnded) {\n            return null;\n        }\n        if (this.audioOutputFormat.hasHeader) {\n            this.privReceivedAudioWithHeader = SynthesisAdapterBase.addHeader(this.allReceivedAudio, this.audioOutputFormat);\n            return this.allReceivedAudioWithHeader;\n        } else {\n            return this.allReceivedAudio;\n        }\n    }\n    private privIsDisposed: boolean = false;\n    private privAuthFetchEventId: string;\n    private privIsSynthesizing: boolean = false;\n    private privIsSynthesisEnded: boolean = false;\n    private privBytesReceived: number = 0;\n    private privRequestId: string;\n    private privStreamId: string;\n    private privTurnDeferral: Deferred<boolean>;\n    private privAudioOutputFormat: AudioOutputFormatImpl;\n    private privAudioOutputStream: PullAudioOutputStreamImpl;\n    private privReceivedAudio: ArrayBuffer;\n    private privReceivedAudioWithHeader: ArrayBuffer;\n    private privTextOffset: number = 0;\n    private privNextSearchTextIndex: number = 0;\n    private privRawText: string;\n    private privIsSSML: boolean;\n    private privTurnAudioDestination: IAudioDestination;\n\n    constructor() {\n        this.privRequestId = createNoDashGuid();\n        this.privTurnDeferral = new Deferred<boolean>();\n\n        // We're not in a turn, so resolve.\n        this.privTurnDeferral.resolve(true);\n    }\n\n    public startNewSynthesis(requestId: string, rawText: string, isSSML: boolean, audioDestination?: IAudioDestination): void {\n        this.privIsSynthesisEnded = false;\n        this.privIsSynthesizing = true;\n        this.privRequestId = requestId;\n        this.privRawText = rawText;\n        this.privIsSSML = isSSML;\n        this.privAudioOutputStream = new PullAudioOutputStreamImpl();\n        this.privAudioOutputStream.format = this.privAudioOutputFormat;\n        this.privReceivedAudio = null;\n        this.privReceivedAudioWithHeader = null;\n        this.privBytesReceived = 0;\n        this.privTextOffset = 0;\n        this.privNextSearchTextIndex = 0;\n        if (audioDestination !== undefined) {\n            this.privTurnAudioDestination = audioDestination;\n            this.privTurnAudioDestination.format = this.privAudioOutputFormat;\n        }\n        this.onEvent(new SynthesisTriggeredEvent(this.requestId, undefined, audioDestination === undefined ? undefined : audioDestination.id()));\n    }\n\n    public onPreConnectionStart = (authFetchEventId: string, connectionId: string): void => {\n        this.privAuthFetchEventId = authFetchEventId;\n        this.onEvent(new ConnectingToSynthesisServiceEvent(this.privRequestId, this.privAuthFetchEventId));\n    }\n\n    public onAuthCompleted = (isError: boolean, error?: string): void => {\n        if (isError) {\n            this.onComplete();\n        }\n    }\n\n    public onConnectionEstablishCompleted = (statusCode: number, reason?: string): void => {\n        if (statusCode === 200) {\n            this.onEvent(new SynthesisStartedEvent(this.requestId, this.privAuthFetchEventId));\n            this.privBytesReceived = 0;\n            return;\n        } else if (statusCode === 403) {\n            this.onComplete();\n        }\n    }\n\n    public onServiceResponseMessage = (responseJson: string): void => {\n        const response: ISynthesisResponse = JSON.parse(responseJson);\n        this.streamId = response.audio.streamId;\n    }\n\n    public onServiceTurnEndResponse = (): void => {\n        this.privTurnDeferral.resolve(true);\n        this.onComplete();\n    }\n\n    public onServiceTurnStartResponse = (): void => {\n        if (this.privTurnDeferral.state() === PromiseState.None) {\n            // What? How are we starting a turn with another not done?\n            this.privTurnDeferral.reject(\"Another turn started before current completed.\");\n        }\n\n        this.privTurnDeferral = new Deferred<boolean>();\n    }\n\n    public onAudioChunkReceived(data: ArrayBuffer): void {\n        if (this.isSynthesizing) {\n            this.privAudioOutputStream.write(data);\n            this.privBytesReceived += data.byteLength;\n            if (this.privTurnAudioDestination !== undefined) {\n                this.privTurnAudioDestination.write(data);\n            }\n        }\n    }\n\n    public onWordBoundaryEvent(text: string): void {\n        this.updateTextOffset(text);\n    }\n\n    public dispose = (error?: string): void => {\n        if (!this.privIsDisposed) {\n            // we should have completed by now. If we did not its an unknown error.\n            this.privIsDisposed = true;\n        }\n    }\n\n    public onStopSynthesizing(): void {\n        this.onComplete();\n    }\n\n    protected onEvent = (event: SpeechSynthesisEvent): void => {\n        Events.instance.onEvent(event);\n    }\n\n    private updateTextOffset(text: string): void {\n        if (this.privTextOffset >= 0) {\n            this.privTextOffset = this.privRawText.indexOf(text, this.privNextSearchTextIndex);\n            if (this.privTextOffset >= 0) {\n                this.privNextSearchTextIndex = this.privTextOffset + text.length;\n            }\n            if (this.privIsSSML) {\n                if (this.privRawText.indexOf(\"<\", this.privTextOffset + 1) > this.privRawText.indexOf(\">\", this.privTextOffset + 1)) {\n                    this.updateTextOffset(text);\n                }\n            }\n        }\n    }\n\n    private onComplete = (): void => {\n        if (this.privIsSynthesizing) {\n            this.privIsSynthesizing = false;\n            this.privIsSynthesisEnded = true;\n            this.privAudioOutputStream.close();\n            if (this.privTurnAudioDestination !== undefined) {\n                this.privTurnAudioDestination.close();\n                this.privTurnAudioDestination = undefined;\n            }\n        }\n    }\n\n    private readAllAudioFromStream(): void {\n        if (this.privIsSynthesisEnded) {\n            this.privReceivedAudio = new ArrayBuffer(this.bytesReceived);\n            try {\n                this.privAudioOutputStream.read(this.privReceivedAudio);\n            } catch (e) {\n                this.privReceivedAudio = new ArrayBuffer(0);\n            }\n        }\n    }\n}\n"]}