UNPKG

@hahnpro/ms-speech-sdk

Version:
1 lines 28.1 kB
{"version":3,"sources":["src/common.speech/SynthesisAdapterBase.ts"],"names":[],"mappings":"AAGA,OAAO,EAGH,eAAe,EAIf,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,WAAW,EAEX,YAAY,EACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EACH,qBAAqB,EACrB,kBAAkB,EAIlB,gCAAgC,EAChC,qBAAqB,EACrB,8BAA8B,EAC9B,oCAAoC,EACpC,WAAW,EACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,WAAW,EAEX,2BAA2B,EAC3B,kBAAkB,EAGlB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAY,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAEhF,8BAAsB,oBAAqB,YAAW,WAAW;IAC7D,SAAS,CAAC,iBAAiB,EAAE,aAAa,CAAC;IAC3C,SAAS,CAAC,gBAAgB,EAAE,MAAM,CAAC;IACnC,SAAS,CAAC,qBAAqB,EAAE,iBAAiB,CAAC;IACnD,SAAS,CAAC,eAAe,EAAE,WAAW,CAAC;IACvC,SAAS,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAClE,SAAS,CAAC,iBAAiB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjD,IAAW,iBAAiB,IAAI,iBAAiB,CAEhD;IAED,IAAW,gBAAgB,IAAI,gBAAgB,CAE9C;IAED,IAAW,WAAW,IAAI,WAAW,CAEpC;IAED,IAAW,gBAAgB,IAAI,WAAW,CAAC,eAAe,CAAC,CAE1D;IAED,IAAW,aAAa,IAAI,WAAW,CAAC,YAAY,CAAC,CAEpD;IAED,SAAS,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,qBAAqB,KAAK,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAa;IAIhJ,OAAc,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,OAAc,oBAAoB,EAAE,OAAO,CAAQ;IAEnD,IAAW,gBAAgB,CAAC,cAAc,EAAE,MAAM,EAEjD;IACD,IAAW,gBAAgB,IAAI,MAAM,CAEpC;IAED,SAAS,CAAC,sBAAsB,EAAE,MAAM,IAAI,CAAa;IAEzD,SAAS,CAAC,mBAAmB,EAAE,CAAC,cAAc,EAAE,OAAO,KAAK,IAAI,CAAa;IAE7E,SAAS,CAAC,wBAAwB,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,OAAO,CAAC,WAAW,CAAC,CAAa;IAElG,IAAW,iBAAiB,CAAC,MAAM,EAAE,qBAAqB,EASzD;IACD,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,qBAAqB,CAA8B;IAI3D,OAAO,CAAC,kCAAkC,CAAmC;IAI7E,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,oBAAoB,CAA+B;IAC3D,OAAO,CAAC,iBAAiB,CAA4B;IACrD,SAAS,CAAC,oBAAoB,EAAE,gBAAgB,CAAC;IACjD,OAAO,CAAC,eAAe,CAAc;IACrC,OAAO,CAAC,oBAAoB,CAAS;IACrC,SAAS,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IACvD,OAAO,CAAC,2BAA2B,CAAoB;gBAGnD,cAAc,EAAE,eAAe,EAC/B,iBAAiB,EAAE,2BAA2B,EAC9C,iBAAiB,EAAE,iBAAiB,EACpC,gBAAgB,EAAE,iBAAiB;IAqChC,UAAU,IAAI,OAAO;IAIf,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9E,KAAK,CACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,CAAC,CAAC,EAAE,qBAAqB,KAAK,IAAI,EACnD,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,EAClC,gBAAgB,EAAE,iBAAiB,GACpC,OAAO,CAAC,IAAI,CAAC;IAiCH,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB1C,SAAS,CAAC,eAAe,CACrB,SAAS,EAAE,MAAM,EACjB,mBAAmB,EAAE,kBAAkB,EACvC,SAAS,EAAE,qBAAqB,EAChC,KAAK,EAAE,MAAM,GAAG,IAAI;IAsBxB,SAAS,CAAC,oBAAoB,CAC1B,kBAAkB,EAAE,kBAAkB,EACtC,SAAS,EAAE,qBAAqB,EAChC,KAAK,EAAE,MAAM,GAAG,IAAI;IAcxB,SAAS,CAAC,2BAA2B,CAAC,kBAAkB,EAAE,uBAAuB,GAAG,OAAO;cAI3E,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAuH/C,SAAS,CAAC,oBAAoB,CAAC,UAAU,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAetE,SAAS,CAAC,QAAQ,CAAC,mCAAmC,IAAI,IAAI;IAE9D,SAAS,CAAC,+BAA+B,IAAI,IAAI;IAIjD,SAAS,CAAC,WAAW,CAAC,cAAc,GAAE,OAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAwD5E,SAAS,CAAC,uBAAuB,CAAC,UAAU,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1G,SAAS,CAAC,eAAe,CAAC,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YASpF,eAAe;YAoBf,mBAAmB;IAUjC,SAAS,CAAC,aAAa,CAAC,SAAS,EAAE,kBAAkB,GAAG,IAAI;IAI5D,SAAS,CAAC,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAItD,SAAS,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAInD,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAIpE,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAIpE,SAAS,CAAC,cAAc,CAAC,sBAAsB,EAAE,oCAAoC,GAAG,IAAI;IAI5F,SAAS,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,8BAA8B,GAAG,IAAI;IAIlF,SAAS,CAAC,iBAAiB,CAAC,kBAAkB,EAAE,gCAAgC,GAAG,IAAI;CAI1F","file":"SynthesisAdapterBase.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nimport {\n ArgumentNullError,\n ConnectionClosedEvent,\n ConnectionEvent,\n ConnectionMessage,\n ConnectionState,\n createNoDashGuid,\n EventSource,\n IAudioDestination,\n IConnection,\n IDisposable,\n MessageType,\n ServiceEvent,\n} from \"../common/Exports.js\";\nimport { AudioOutputFormatImpl } from \"../sdk/Audio/AudioOutputFormat.js\";\nimport {\n CancellationErrorCode,\n CancellationReason,\n PropertyCollection,\n PropertyId,\n ResultReason,\n SpeechSynthesisBookmarkEventArgs,\n SpeechSynthesisResult,\n SpeechSynthesisVisemeEventArgs,\n SpeechSynthesisWordBoundaryEventArgs,\n Synthesizer,\n} from \"../sdk/Exports.js\";\nimport {\n AgentConfig,\n CancellationErrorCodePropertyName,\n ISynthesisConnectionFactory,\n ISynthesisMetadata,\n MetadataType,\n SynthesisAudioMetadata,\n SynthesisContext,\n SynthesisTurn,\n SynthesizerConfig\n} from \"./Exports.js\";\nimport { AuthInfo, IAuthentication } from \"./IAuthentication.js\";\nimport { SpeechConnectionMessage } from \"./SpeechConnectionMessage.Internal.js\";\n\nexport abstract class SynthesisAdapterBase implements IDisposable {\n protected privSynthesisTurn: SynthesisTurn;\n protected privConnectionId: string;\n protected privSynthesizerConfig: SynthesizerConfig;\n protected privSynthesizer: Synthesizer;\n protected privSuccessCallback: (e: SpeechSynthesisResult) => void;\n protected privErrorCallback: (e: string) => void;\n\n public get synthesizerConfig(): SynthesizerConfig {\n return this.privSynthesizerConfig;\n }\n\n public get synthesisContext(): SynthesisContext {\n return this.privSynthesisContext;\n }\n\n public get agentConfig(): AgentConfig {\n return this.privAgentConfig;\n }\n\n public get connectionEvents(): EventSource<ConnectionEvent> {\n return this.privConnectionEvents;\n }\n\n public get serviceEvents(): EventSource<ServiceEvent> {\n return this.privServiceEvents;\n }\n\n protected speakOverride: (ssml: string, requestId: string, sc: (e: SpeechSynthesisResult) => void, ec: (e: string) => void) => void = undefined;\n\n // Called when telemetry data is sent to the service.\n // Used for testing Telemetry capture.\n public static telemetryData: (json: string) => void;\n public static telemetryDataEnabled: boolean = true;\n\n public set activityTemplate(messagePayload: string) {\n this.privActivityTemplate = messagePayload;\n }\n public get activityTemplate(): string {\n return this.privActivityTemplate;\n }\n\n protected receiveMessageOverride: () => void = undefined;\n\n protected connectImplOverride: (isUnAuthorized: boolean) => void = undefined;\n\n protected configConnectionOverride: (connection: IConnection) => Promise<IConnection> = undefined;\n\n public set audioOutputFormat(format: AudioOutputFormatImpl) {\n this.privAudioOutputFormat = format;\n this.privSynthesisTurn.audioOutputFormat = format;\n if (this.privSessionAudioDestination !== undefined) {\n this.privSessionAudioDestination.format = format;\n }\n if (this.synthesisContext !== undefined) {\n this.synthesisContext.audioOutputFormat = format;\n }\n }\n private privAuthentication: IAuthentication;\n private privConnectionFactory: ISynthesisConnectionFactory;\n\n // A promise for a configured connection.\n // Do not consume directly, call fetchConnection instead.\n private privConnectionConfigurationPromise: Promise<IConnection> = undefined;\n\n // A promise for a connection, but one that has not had the speech context sent yet.\n // Do not consume directly, call fetchConnection instead.\n private privConnectionPromise: Promise<IConnection>;\n private privAuthFetchEventId: string;\n private privIsDisposed: boolean;\n private privConnectionEvents: EventSource<ConnectionEvent>;\n private privServiceEvents: EventSource<ServiceEvent>;\n protected privSynthesisContext: SynthesisContext;\n private privAgentConfig: AgentConfig;\n private privActivityTemplate: string;\n protected privAudioOutputFormat: AudioOutputFormatImpl;\n private privSessionAudioDestination: IAudioDestination;\n\n public constructor(\n authentication: IAuthentication,\n connectionFactory: ISynthesisConnectionFactory,\n synthesizerConfig: SynthesizerConfig,\n audioDestination: IAudioDestination) {\n\n if (!authentication) {\n throw new ArgumentNullError(\"authentication\");\n }\n\n if (!connectionFactory) {\n throw new ArgumentNullError(\"connectionFactory\");\n }\n\n if (!synthesizerConfig) {\n throw new ArgumentNullError(\"synthesizerConfig\");\n }\n\n this.privAuthentication = authentication;\n this.privConnectionFactory = connectionFactory;\n this.privSynthesizerConfig = synthesizerConfig;\n this.privIsDisposed = false;\n this.privSessionAudioDestination = audioDestination;\n this.privSynthesisTurn = new SynthesisTurn();\n this.privConnectionEvents = new EventSource<ConnectionEvent>();\n this.privServiceEvents = new EventSource<ServiceEvent>();\n this.privSynthesisContext = new SynthesisContext();\n this.privAgentConfig = new AgentConfig();\n\n this.connectionEvents.attach((connectionEvent: ConnectionEvent): void => {\n if (connectionEvent.name === \"ConnectionClosedEvent\") {\n const connectionClosedEvent = connectionEvent as ConnectionClosedEvent;\n if (connectionClosedEvent.statusCode !== 1000) {\n this.cancelSynthesisLocal(CancellationReason.Error,\n connectionClosedEvent.statusCode === 1007 ? CancellationErrorCode.BadRequestParameters : CancellationErrorCode.ConnectionFailure,\n `${connectionClosedEvent.reason} websocket error code: ${connectionClosedEvent.statusCode}`);\n }\n }\n });\n }\n\n public isDisposed(): boolean {\n return this.privIsDisposed;\n }\n\n public async dispose(reason?: string): Promise<void> {\n this.privIsDisposed = true;\n if (this.privSessionAudioDestination !== undefined) {\n this.privSessionAudioDestination.close();\n }\n if (this.privConnectionConfigurationPromise !== undefined) {\n const connection: IConnection = await this.privConnectionConfigurationPromise;\n await connection.dispose(reason);\n }\n }\n\n public async connect(): Promise<void> {\n await this.connectImpl();\n }\n\n public async sendNetworkMessage(path: string, payload: string | ArrayBuffer): Promise<void> {\n const type: MessageType = typeof payload === \"string\" ? MessageType.Text : MessageType.Binary;\n const contentType: string = typeof payload === \"string\" ? \"application/json\" : \"\";\n\n const connection: IConnection = await this.fetchConnection();\n return connection.send(new SpeechConnectionMessage(type, path, this.privSynthesisTurn.requestId, contentType, payload));\n }\n\n public async Speak(\n text: string,\n isSSML: boolean,\n requestId: string,\n successCallback: (e: SpeechSynthesisResult) => void,\n errorCallBack: (e: string) => void,\n audioDestination: IAudioDestination,\n ): Promise<void> {\n\n let ssml: string;\n\n if (isSSML) {\n ssml = text;\n } else {\n ssml = this.privSynthesizer.buildSsml(text);\n }\n\n if (this.speakOverride !== undefined) {\n return this.speakOverride(ssml, requestId, successCallback, errorCallBack);\n }\n\n this.privSuccessCallback = successCallback;\n this.privErrorCallback = errorCallBack;\n\n this.privSynthesisTurn.startNewSynthesis(requestId, text, isSSML, audioDestination);\n\n try {\n await this.connectImpl();\n const connection: IConnection = await this.fetchConnection();\n await this.sendSynthesisContext(connection);\n await this.sendSsmlMessage(connection, ssml, requestId);\n this.onSynthesisStarted(requestId);\n\n void this.receiveMessage();\n } catch (e) {\n this.cancelSynthesisLocal(CancellationReason.Error, CancellationErrorCode.ConnectionFailure, e as string);\n return Promise.reject(e);\n }\n }\n\n public async stopSpeaking(): Promise<void> {\n await this.connectImpl();\n const connection: IConnection = await this.fetchConnection();\n\n return connection.send(new SpeechConnectionMessage(\n MessageType.Text,\n \"synthesis.control\",\n this.privSynthesisTurn.requestId,\n \"application/json\",\n JSON.stringify({\n action: \"stop\"\n })\n ));\n }\n\n // Cancels synthesis.\n protected cancelSynthesis(\n requestId: string,\n _cancellationReason: CancellationReason,\n errorCode: CancellationErrorCode,\n error: string): void {\n const properties: PropertyCollection = new PropertyCollection();\n properties.setProperty(CancellationErrorCodePropertyName, CancellationErrorCode[errorCode]);\n const result: SpeechSynthesisResult = new SpeechSynthesisResult(\n requestId,\n ResultReason.Canceled,\n undefined,\n error,\n properties\n );\n\n this.onSynthesisCancelled(result);\n\n if (!!this.privSuccessCallback) {\n try {\n this.privSuccessCallback(result);\n /* eslint-disable no-empty */\n } catch { }\n }\n }\n\n // Cancels synthesis.\n protected cancelSynthesisLocal(\n cancellationReason: CancellationReason,\n errorCode: CancellationErrorCode,\n error: string): void {\n\n if (!!this.privSynthesisTurn.isSynthesizing) {\n this.privSynthesisTurn.onStopSynthesizing();\n\n this.cancelSynthesis(\n this.privSynthesisTurn.requestId,\n cancellationReason,\n errorCode,\n error);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected processTypeSpecificMessages(_connectionMessage: SpeechConnectionMessage): boolean {\n return true;\n }\n\n protected async receiveMessage(): Promise<void> {\n try {\n const connection: IConnection = await this.fetchConnection();\n const message: ConnectionMessage = await connection.read();\n\n if (this.receiveMessageOverride !== undefined) {\n return this.receiveMessageOverride();\n }\n if (this.privIsDisposed) {\n // We're done.\n return;\n }\n\n // indicates we are draining the queue and it came with no message;\n if (!message) {\n if (!this.privSynthesisTurn.isSynthesizing) {\n return;\n } else {\n return this.receiveMessage();\n }\n }\n\n\n const connectionMessage = SpeechConnectionMessage.fromConnectionMessage(message);\n\n if (connectionMessage.requestId.toLowerCase() === this.privSynthesisTurn.requestId.toLowerCase()) {\n switch (connectionMessage.path.toLowerCase()) {\n case \"turn.start\":\n this.privSynthesisTurn.onServiceTurnStartResponse(connectionMessage.textBody);\n break;\n case \"response\":\n this.privSynthesisTurn.onServiceResponseMessage(connectionMessage.textBody);\n break;\n case \"audio\":\n if (this.privSynthesisTurn.streamId.toLowerCase() === connectionMessage.streamId.toLowerCase()\n && !!connectionMessage.binaryBody) {\n this.privSynthesisTurn.onAudioChunkReceived(connectionMessage.binaryBody);\n this.onSynthesizing(connectionMessage.binaryBody);\n if (this.privSessionAudioDestination !== undefined) {\n this.privSessionAudioDestination.write(connectionMessage.binaryBody);\n }\n }\n break;\n case \"audio.metadata\":\n const metadataList = SynthesisAudioMetadata.fromJSON(connectionMessage.textBody).Metadata;\n for (const metadata of metadataList) {\n switch (metadata.Type) {\n case MetadataType.WordBoundary:\n case MetadataType.SentenceBoundary:\n this.privSynthesisTurn.onTextBoundaryEvent(metadata);\n const wordBoundaryEventArgs: SpeechSynthesisWordBoundaryEventArgs = new SpeechSynthesisWordBoundaryEventArgs(\n metadata.Data.Offset,\n metadata.Data.Duration,\n metadata.Data.text.Text,\n metadata.Data.text.Length,\n metadata.Type === MetadataType.WordBoundary\n ? this.privSynthesisTurn.currentTextOffset : this.privSynthesisTurn.currentSentenceOffset,\n metadata.Data.text.BoundaryType);\n this.onWordBoundary(wordBoundaryEventArgs);\n break;\n case MetadataType.Bookmark:\n const bookmarkEventArgs: SpeechSynthesisBookmarkEventArgs = new SpeechSynthesisBookmarkEventArgs(\n metadata.Data.Offset,\n metadata.Data.Bookmark);\n this.onBookmarkReached(bookmarkEventArgs);\n break;\n case MetadataType.Viseme:\n this.privSynthesisTurn.onVisemeMetadataReceived(metadata);\n if (metadata.Data.IsLastAnimation) {\n const visemeEventArgs: SpeechSynthesisVisemeEventArgs = new SpeechSynthesisVisemeEventArgs(\n metadata.Data.Offset,\n metadata.Data.VisemeId,\n this.privSynthesisTurn.getAndClearVisemeAnimation());\n this.onVisemeReceived(visemeEventArgs);\n }\n break;\n case MetadataType.AvatarSignal:\n this.onAvatarEvent(metadata);\n break;\n case MetadataType.SessionEnd:\n this.privSynthesisTurn.onSessionEnd(metadata);\n break;\n }\n }\n break;\n case \"turn.end\":\n this.privSynthesisTurn.onServiceTurnEndResponse();\n let result: SpeechSynthesisResult;\n try {\n result = await this.privSynthesisTurn.constructSynthesisResult();\n if (!!this.privSuccessCallback) {\n this.privSuccessCallback(result);\n }\n } catch (error) {\n if (!!this.privErrorCallback) {\n this.privErrorCallback(error as string);\n }\n }\n this.onSynthesisCompleted(result);\n break;\n\n default:\n if (!this.processTypeSpecificMessages(connectionMessage)) {\n // here are some messages that the derived class has not processed, dispatch them to connect class\n if (!!this.privServiceEvents) {\n this.serviceEvents.onEvent(new ServiceEvent(connectionMessage.path.toLowerCase(), connectionMessage.textBody));\n }\n }\n\n }\n }\n\n return this.receiveMessage();\n\n } catch (e) {\n // TODO: What goes here?\n }\n }\n\n protected sendSynthesisContext(connection: IConnection): Promise<void> {\n this.setSynthesisContextSynthesisSection();\n const synthesisContextJson = this.synthesisContext.toJSON();\n\n if (synthesisContextJson) {\n return connection.send(new SpeechConnectionMessage(\n MessageType.Text,\n \"synthesis.context\",\n this.privSynthesisTurn.requestId,\n \"application/json\",\n synthesisContextJson));\n }\n return;\n }\n\n protected abstract setSynthesisContextSynthesisSection(): void;\n\n protected setSpeechConfigSynthesisSection(): void {\n return;\n }\n\n protected connectImpl(isUnAuthorized: boolean = false): Promise<IConnection> {\n if (this.privConnectionPromise != null) {\n return this.privConnectionPromise.then((connection: IConnection): Promise<IConnection> => {\n if (connection.state() === ConnectionState.Disconnected) {\n this.privConnectionId = null;\n this.privConnectionPromise = null;\n return this.connectImpl();\n }\n return this.privConnectionPromise;\n }, (): Promise<IConnection> => {\n this.privConnectionId = null;\n this.privConnectionPromise = null;\n return this.connectImpl();\n });\n }\n this.privAuthFetchEventId = createNoDashGuid();\n this.privConnectionId = createNoDashGuid();\n\n this.privSynthesisTurn.onPreConnectionStart(this.privAuthFetchEventId);\n\n const authPromise = isUnAuthorized ? this.privAuthentication.fetchOnExpiry(this.privAuthFetchEventId) : this.privAuthentication.fetch(this.privAuthFetchEventId);\n\n this.privConnectionPromise = authPromise.then(async (result: AuthInfo): Promise<IConnection> => {\n this.privSynthesisTurn.onAuthCompleted(false);\n\n const connection: IConnection = await this.privConnectionFactory.create(this.privSynthesizerConfig, result, this.privConnectionId);\n\n // Attach to the underlying event. No need to hold onto the detach pointers as in the event the connection goes away,\n // it'll stop sending events.\n connection.events.attach((event: ConnectionEvent): void => {\n this.connectionEvents.onEvent(event);\n });\n const response = await connection.open();\n if (response.statusCode === 200) {\n this.privSynthesisTurn.onConnectionEstablishCompleted(response.statusCode);\n return Promise.resolve(connection);\n } else if (response.statusCode === 403 && !isUnAuthorized) {\n return this.connectImpl(true);\n } else {\n this.privSynthesisTurn.onConnectionEstablishCompleted(response.statusCode);\n return Promise.reject(\n `Unable to contact server. StatusCode: ${response.statusCode},\n ${this.privSynthesizerConfig.parameters.getProperty(PropertyId.SpeechServiceConnection_Url)} Reason: ${response.reason}`);\n }\n }, (error: string): Promise<IConnection> => {\n this.privSynthesisTurn.onAuthCompleted(true);\n throw new Error(error);\n });\n\n // Attach an empty handler to allow the promise to run in the background while\n // other startup events happen. It'll eventually be awaited on.\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n this.privConnectionPromise.catch((): void => { });\n\n return this.privConnectionPromise;\n }\n protected sendSpeechServiceConfig(connection: IConnection, SpeechServiceConfigJson: string): Promise<void> {\n if (SpeechServiceConfigJson) {\n return connection.send(new SpeechConnectionMessage(\n MessageType.Text,\n \"speech.config\",\n this.privSynthesisTurn.requestId,\n \"application/json\",\n SpeechServiceConfigJson));\n }\n }\n\n protected sendSsmlMessage(connection: IConnection, ssml: string, requestId: string): Promise<void> {\n return connection.send(new SpeechConnectionMessage(\n MessageType.Text,\n \"ssml\",\n requestId,\n \"application/ssml+xml\",\n ssml));\n }\n\n private async fetchConnection(): Promise<IConnection> {\n if (this.privConnectionConfigurationPromise !== undefined) {\n return this.privConnectionConfigurationPromise.then((connection: IConnection): Promise<IConnection> => {\n if (connection.state() === ConnectionState.Disconnected) {\n this.privConnectionId = null;\n this.privConnectionConfigurationPromise = undefined;\n return this.fetchConnection();\n }\n return this.privConnectionConfigurationPromise;\n }, (): Promise<IConnection> => {\n this.privConnectionId = null;\n this.privConnectionConfigurationPromise = undefined;\n return this.fetchConnection();\n });\n }\n this.privConnectionConfigurationPromise = this.configureConnection();\n return await this.privConnectionConfigurationPromise;\n }\n\n // Takes an established websocket connection to the endpoint and sends speech configuration information.\n private async configureConnection(): Promise<IConnection> {\n const connection: IConnection = await this.connectImpl();\n if (this.configConnectionOverride !== undefined) {\n return this.configConnectionOverride(connection);\n }\n this.setSpeechConfigSynthesisSection();\n await this.sendSpeechServiceConfig(connection, this.privSynthesizerConfig.SpeechServiceConfig.serialize());\n return connection;\n }\n\n protected onAvatarEvent(_metadata: ISynthesisMetadata): void {\n return;\n }\n\n protected onSynthesisStarted(_requestId: string): void {\n return;\n }\n\n protected onSynthesizing(_audio: ArrayBuffer): void {\n return;\n }\n\n protected onSynthesisCancelled(_result: SpeechSynthesisResult): void {\n return;\n }\n\n protected onSynthesisCompleted(_result: SpeechSynthesisResult): void {\n return;\n }\n\n protected onWordBoundary(_wordBoundaryEventArgs: SpeechSynthesisWordBoundaryEventArgs): void {\n return;\n }\n\n protected onVisemeReceived(_visemeEventArgs: SpeechSynthesisVisemeEventArgs): void {\n return;\n }\n\n protected onBookmarkReached(_bookmarkEventArgs: SpeechSynthesisBookmarkEventArgs): void {\n return;\n }\n\n}\n"]}