UNPKG

@voice-ping/cognitive-services-speech

Version:

VoicePing Cognitive Services Speech SDK for JavaScript forked from Microsoft

1 lines 35.8 kB
{"version":3,"sources":["src/common.speech/Transcription/ConversationServiceAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,EAEH,iBAAiB,EAKjB,YAAY,EACZ,WAAW,EAEX,OAAO,EAGV,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,qBAAqB,EACrB,kBAAkB,EAQrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACO,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,qBAAqB,EACzF,MAAM,YAAY,CAAC;AAYpB,OAAO,EAAE,gCAAgC,EAAE,MAAM,oCAAoC,CAAC;AAYtF;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,qBAAqB;IACjE,OAAO,CAAC,gCAAgC,CAAmC;IAC3E,OAAO,CAAC,iCAAiC,CAAqB;IAC9D,OAAO,CAAC,gCAAgC,CAAS;IACjD,OAAO,CAAC,8BAA8B,CAAkB;IACxD,OAAO,CAAC,8BAA8B,CAA6B;IACnE,OAAO,CAAC,2BAA2B,CAAuB;IAC1D,OAAO,CAAC,iCAAiC,CAAuB;IAChE,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,oBAAoB,CAAU;IACtC,OAAO,CAAC,0BAA0B,CAAc;IAChD,OAAO,CAAC,0BAA0B,CAAU;gBAGxC,cAAc,EAAE,eAAe,EAC/B,iBAAiB,EAAE,kBAAkB,EACrC,WAAW,EAAE,YAAY,EACzB,gBAAgB,EAAE,gBAAgB,EAClC,4BAA4B,EAAE,gCAAgC;IAiB3D,UAAU,IAAI,OAAO;IAIrB,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAS9B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQlC,gBAAgB,wCA2BtB;IAED,SAAS,CAAC,cAAc,IAAI,IAAI;IAuBhC,SAAS,CAAC,2BAA2B,CACjC,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,EAClC,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;IAKjD,SAAS,CAAC,iBAAiB,CACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,kBAAkB,EACtC,SAAS,EAAE,qBAAqB,EAChC,KAAK,EAAE,MAAM,GAAG,IAAI;IAoBxB,SAAS,CAAC,IAAI,YAEb;IAED;;;OAGG;IACH,SAAS,CAAC,uBAAuB,CAAC,cAAc,GAAE,OAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAiExF;;OAEG;IACH,OAAO,CAAC,kCAAkC,CAuUzC;IAED,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,2BAA2B,CAElC;CAEJ","file":"ConversationServiceAdapter.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nimport {\n ConnectionEvent,\n ConnectionMessage,\n ConnectionOpenResponse,\n ConnectionState,\n createNoDashGuid,\n Deferred,\n IAudioSource,\n IConnection,\n MessageType,\n Promise,\n PromiseHelper,\n PromiseResult\n} from \"../../common/Exports\";\nimport { Sink } from \"../../common/Promise\";\nimport {\n CancellationErrorCode,\n CancellationReason,\n ConversationExpirationEventArgs,\n ConversationTranslationCanceledEventArgs,\n ConversationTranslationResult,\n PropertyId,\n SessionEventArgs,\n SpeechRecognitionResult,\n Translations\n} from \"../../sdk/Exports\";\nimport {\n AuthInfo, IAuthentication, IConnectionFactory, RecognizerConfig, ServiceRecognizerBase\n} from \"../Exports\";\nimport { ConversationConnectionMessage } from \"./ConversationConnectionMessage\";\nimport { ConversationRequestSession } from \"./ConversationRequestSession\";\nimport {\n ConversationReceivedTranslationEventArgs,\n LockRoomEventArgs,\n MuteAllEventArgs,\n ParticipantAttributeEventArgs,\n ParticipantEventArgs,\n ParticipantsListEventArgs\n} from \"./ConversationTranslatorEventArgs\";\nimport { ConversationTranslatorCommandTypes, ConversationTranslatorMessageTypes, IInternalParticipant } from \"./ConversationTranslatorInterfaces\";\nimport { ConversationTranslatorRecognizer } from \"./ConversationTranslatorRecognizer\";\nimport {\n CommandResponsePayload,\n IParticipantPayloadResponse,\n IParticipantsListPayloadResponse,\n ITranslationResponsePayload,\n ParticipantPayloadResponse,\n ParticipantsListPayloadResponse,\n SpeechResponsePayload,\n TextResponsePayload\n} from \"./ServiceMessages/Exports\";\n\n/***\n * The service adapter handles sending and receiving messages to the Conversation Translator websocket.\n */\nexport class ConversationServiceAdapter extends ServiceRecognizerBase {\n private privConversationServiceConnector: ConversationTranslatorRecognizer;\n private privConversationConnectionFactory: IConnectionFactory;\n private privConversationAuthFetchEventId: string;\n private privConversationAuthentication: IAuthentication;\n private privConversationRequestSession: ConversationRequestSession;\n private privConnectionConfigPromise: Promise<IConnection>;\n private privConversationConnectionPromise: Promise<IConnection>;\n private privConnectionLoop: Promise<IConnection>;\n private terminateMessageLoop: boolean;\n private privLastPartialUtteranceId: string = \"\";\n private privConversationIsDisposed: boolean;\n\n public constructor(\n authentication: IAuthentication,\n connectionFactory: IConnectionFactory,\n audioSource: IAudioSource,\n recognizerConfig: RecognizerConfig,\n conversationServiceConnector: ConversationTranslatorRecognizer) {\n\n super(authentication, connectionFactory, audioSource, recognizerConfig, conversationServiceConnector);\n\n this.privConversationServiceConnector = conversationServiceConnector;\n this.privConversationAuthentication = authentication;\n this.receiveMessageOverride = this.receiveConversationMessageOverride;\n this.recognizeOverride = this.noOp;\n this.connectImplOverride = this.conversationConnectImpl;\n this.configConnectionOverride = this.configConnection;\n this.fetchConnectionOverride = this.fetchConversationConnection;\n this.disconnectOverride = this.privDisconnect;\n this.privConversationRequestSession = new ConversationRequestSession(createNoDashGuid());\n this.privConversationConnectionFactory = connectionFactory;\n this.privConversationIsDisposed = false;\n }\n\n public isDisposed(): boolean {\n return this.privConversationIsDisposed;\n }\n\n public dispose(reason?: string): void {\n this.privConversationIsDisposed = true;\n if (this.privConnectionConfigPromise) {\n this.privConnectionConfigPromise.onSuccessContinueWith((connection: IConnection) => {\n connection.dispose(reason);\n });\n }\n }\n\n public sendMessage(message: string): void {\n this.fetchConversationConnection().onSuccessContinueWith((connection: IConnection) => {\n connection.send(new ConversationConnectionMessage(\n MessageType.Text,\n message));\n });\n }\n\n public sendMessageAsync = (message: string): Promise<boolean> => {\n const sink: Sink<boolean> = new Sink<boolean>();\n\n this.fetchConversationConnection().continueWith((antecedent: PromiseResult<IConnection>): void => {\n try {\n if (antecedent.isError) {\n sink.reject(antecedent.error);\n } else {\n antecedent.result.send(new ConversationConnectionMessage(MessageType.Text, message))\n .continueWith((innerAntecedent: PromiseResult<boolean>): void => {\n try {\n if (innerAntecedent.isError) {\n sink.reject(innerAntecedent.error);\n } else {\n sink.resolve(innerAntecedent.result);\n }\n } catch (e) {\n sink.reject(`Unhandled inner error: ${e}`);\n }\n });\n }\n } catch (e) {\n sink.reject(`Unhandled error: ${e}`);\n }\n });\n\n return new Promise<boolean>(sink);\n }\n\n protected privDisconnect(): void {\n if (this.terminateMessageLoop) {\n return;\n }\n this.cancelRecognition(this.privConversationRequestSession.sessionId,\n this.privConversationRequestSession.requestId,\n CancellationReason.Error,\n CancellationErrorCode.NoError,\n \"Disconnecting\");\n\n this.terminateMessageLoop = true;\n if (this.privConversationConnectionPromise.result().isCompleted) {\n if (!this.privConversationConnectionPromise.result().isError) {\n this.privConversationConnectionPromise.result().result.dispose();\n this.privConversationConnectionPromise = null;\n }\n } else {\n this.privConversationConnectionPromise.onSuccessContinueWith((connection: IConnection) => {\n connection.dispose();\n });\n }\n }\n\n protected processTypeSpecificMessages(\n connectionMessage: ConnectionMessage,\n successCallback?: (e: any) => void,\n errorCallBack?: (e: string) => void): boolean {\n return true;\n }\n\n // Cancels recognition.\n protected cancelRecognition(\n sessionId: string,\n requestId: string,\n cancellationReason: CancellationReason,\n errorCode: CancellationErrorCode,\n error: string): void {\n\n this.terminateMessageLoop = true;\n\n const cancelEvent: ConversationTranslationCanceledEventArgs = new ConversationTranslationCanceledEventArgs(\n cancellationReason,\n error,\n errorCode,\n undefined,\n sessionId);\n\n try {\n if (!!this.privConversationServiceConnector.canceled) {\n this.privConversationServiceConnector.canceled(this.privConversationServiceConnector, cancelEvent);\n }\n } catch {\n // continue on error\n }\n }\n\n protected noOp = (): any => {\n // operation not supported\n }\n\n /**\n * Establishes a websocket connection to the end point.\n * @param isUnAuthorized\n */\n protected conversationConnectImpl(isUnAuthorized: boolean = false): Promise<IConnection> {\n\n if (this.privConversationConnectionPromise) {\n if (this.privConversationConnectionPromise.result().isCompleted &&\n (this.privConversationConnectionPromise.result().isError\n || this.privConversationConnectionPromise.result().result.state() === ConnectionState.Disconnected)) {\n this.privConnectionId = null;\n this.privConversationConnectionPromise = null;\n this.terminateMessageLoop = true;\n return this.conversationConnectImpl();\n } else {\n return this.privConversationConnectionPromise;\n }\n }\n\n this.privConversationAuthFetchEventId = createNoDashGuid();\n\n // keep the connectionId for reconnect events\n if (this.privConnectionId === undefined) {\n this.privConnectionId = createNoDashGuid();\n }\n\n this.privConversationRequestSession.onPreConnectionStart(this.privConversationAuthFetchEventId, this.privConnectionId);\n\n const authPromise = isUnAuthorized ? this.privConversationAuthentication.fetchOnExpiry(this.privConversationAuthFetchEventId) : this.privConversationAuthentication.fetch(this.privConversationAuthFetchEventId);\n\n this.privConversationConnectionPromise = authPromise\n .continueWithPromise((result: PromiseResult<AuthInfo>) => {\n if (result.isError) {\n this.privConversationRequestSession.onAuthCompleted(true, result.error);\n throw new Error(result.error);\n } else {\n this.privConversationRequestSession.onAuthCompleted(false);\n }\n\n const connection: IConnection = this.privConversationConnectionFactory.create(this.privRecognizerConfig, result.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) => {\n this.connectionEvents.onEvent(event);\n });\n\n return connection.open().onSuccessContinueWithPromise((response: ConnectionOpenResponse): Promise<IConnection> => {\n if (response.statusCode === 200) {\n this.privConversationRequestSession.onPreConnectionStart(this.privConversationAuthFetchEventId, this.privConnectionId);\n this.privConversationRequestSession.onConnectionEstablishCompleted(response.statusCode);\n const sessionStartEventArgs: SessionEventArgs = new SessionEventArgs(this.privConversationRequestSession.sessionId);\n if (!!this.privConversationServiceConnector.connectionOpened) {\n this.privConversationServiceConnector.connectionOpened(this.privConversationServiceConnector, sessionStartEventArgs);\n }\n return PromiseHelper.fromResult<IConnection>(connection);\n } else if (response.statusCode === 403 && !isUnAuthorized) {\n return this.conversationConnectImpl(true);\n } else {\n this.privConversationRequestSession.onConnectionEstablishCompleted(response.statusCode, response.reason);\n return PromiseHelper.fromError<IConnection>(`Unable to contact server. StatusCode: ${response.statusCode}, ${this.privRecognizerConfig.parameters.getProperty(PropertyId.SpeechServiceConnection_Endpoint)} Reason: ${response.reason}`);\n }\n });\n });\n\n this.privConnectionLoop = this.startMessageLoop();\n return this.privConversationConnectionPromise;\n }\n\n /**\n * Process incoming websocket messages\n */\n private receiveConversationMessageOverride = (\n successCallback?: (e: any) => void,\n errorCallBack?: (e: string) => void\n ): Promise<IConnection> => {\n\n // we won't rely on the cascading promises of the connection since we want to continually be available to receive messages\n const communicationCustodian: Deferred<IConnection> = new Deferred<IConnection>();\n\n this.fetchConversationConnection().on((connection: IConnection): Promise<IConnection> => {\n return connection.read().onSuccessContinueWithPromise((message: ConversationConnectionMessage): Promise<IConnection> => {\n const isDisposed: boolean = this.isDisposed();\n const terminateMessageLoop = (!this.isDisposed() && this.terminateMessageLoop);\n const sessionId: string = this.privConversationRequestSession.sessionId;\n let sendFinal: boolean = false;\n if (isDisposed || terminateMessageLoop) {\n // We're done.\n communicationCustodian.resolve(undefined);\n return PromiseHelper.fromResult<IConnection>(undefined);\n }\n\n if (!message) {\n return this.receiveConversationMessageOverride();\n }\n\n try {\n switch (message.conversationMessageType.toLowerCase()) {\n case \"info\":\n case \"participant_command\":\n case \"command\":\n const commandPayload: CommandResponsePayload = CommandResponsePayload.fromJSON(message.textBody);\n switch (commandPayload.command.toLowerCase()) {\n\n /**\n * 'ParticpantList' is the first message sent to the user after the websocket connection has opened.\n * The consuming client must wait for this message to arrive\n * before starting to send their own data.\n */\n case \"participantlist\":\n\n const participantsPayload: IParticipantsListPayloadResponse = ParticipantsListPayloadResponse.fromJSON(message.textBody);\n\n const participantsResult: IInternalParticipant[] = participantsPayload.participants.map((p: IParticipantPayloadResponse) => {\n const participant: IInternalParticipant = {\n avatar: p.avatar,\n displayName: p.nickname,\n id: p.participantId,\n isHost: p.ishost,\n isMuted: p.ismuted,\n isUsingTts: p.usetts,\n preferredLanguage: p.locale\n };\n return participant;\n });\n\n if (!!this.privConversationServiceConnector.participantsListReceived) {\n this.privConversationServiceConnector.participantsListReceived(this.privConversationServiceConnector,\n new ParticipantsListEventArgs(participantsPayload.roomid, participantsPayload.token,\n participantsPayload.translateTo, participantsPayload.profanityFilter,\n participantsPayload.roomProfanityFilter, participantsPayload.roomLocked,\n participantsPayload.muteAll, participantsResult, sessionId));\n }\n break;\n\n /**\n * 'SetTranslateToLanguages' represents the list of languages being used in the Conversation by all users(?).\n * This is sent at the start of the Conversation\n */\n case \"settranslatetolanguages\":\n\n if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\n this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\n new ParticipantAttributeEventArgs(commandPayload.participantId,\n ConversationTranslatorCommandTypes.setTranslateToLanguages,\n commandPayload.value, sessionId));\n }\n\n break;\n\n /**\n * 'SetProfanityFiltering' lets the client set the level of profanity filtering.\n * If sent by the participant the setting will effect only their own profanity level.\n * If sent by the host, the setting will effect all participants including the host.\n * Note: the profanity filters differ from Speech Service (?): 'marked', 'raw', 'removed', 'tagged'\n */\n case \"setprofanityfiltering\":\n\n if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\n this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\n new ParticipantAttributeEventArgs(commandPayload.participantId,\n ConversationTranslatorCommandTypes.setProfanityFiltering,\n commandPayload.value, sessionId));\n }\n\n break;\n\n /**\n * 'SetMute' is sent if the participant has been muted by the host.\n * Check the 'participantId' to determine if the current user has been muted.\n */\n case \"setmute\":\n\n if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\n this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\n new ParticipantAttributeEventArgs(commandPayload.participantId,\n ConversationTranslatorCommandTypes.setMute,\n commandPayload.value, sessionId));\n }\n\n break;\n\n /**\n * 'SetMuteAll' is sent if the Conversation has been muted by the host.\n */\n case \"setmuteall\":\n\n if (!!this.privConversationServiceConnector.muteAllCommandReceived) {\n this.privConversationServiceConnector.muteAllCommandReceived(this.privConversationServiceConnector,\n new MuteAllEventArgs(commandPayload.value as boolean, sessionId));\n }\n\n break;\n\n /**\n * 'RoomExpirationWarning' is sent towards the end of the Conversation session to give a timeout warning.\n */\n case \"roomexpirationwarning\":\n\n if (!!this.privConversationServiceConnector.conversationExpiration) {\n this.privConversationServiceConnector.conversationExpiration(this.privConversationServiceConnector,\n new ConversationExpirationEventArgs(commandPayload.value as number, this.privConversationRequestSession.sessionId));\n }\n\n break;\n\n /**\n * 'SetUseTts' is sent as a confirmation if the user requests TTS to be turned on or off.\n */\n case \"setusetts\":\n\n if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\n this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\n new ParticipantAttributeEventArgs(commandPayload.participantId,\n ConversationTranslatorCommandTypes.setUseTTS,\n commandPayload.value, sessionId));\n }\n\n break;\n\n /**\n * 'SetLockState' is set if the host has locked or unlocked the Conversation.\n */\n case \"setlockstate\":\n\n if (!!this.privConversationServiceConnector.lockRoomCommandReceived) {\n this.privConversationServiceConnector.lockRoomCommandReceived(this.privConversationServiceConnector,\n new LockRoomEventArgs(commandPayload.value as boolean, sessionId));\n }\n\n break;\n\n /**\n * 'ChangeNickname' is received if a user changes their display name.\n * Any cached particpiants list should be updated to reflect the display name.\n */\n case \"changenickname\":\n\n if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\n this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\n new ParticipantAttributeEventArgs(commandPayload.participantId,\n ConversationTranslatorCommandTypes.changeNickname,\n commandPayload.nickname, sessionId));\n }\n\n break;\n\n /**\n * 'JoinSession' is sent when a user joins the Conversation.\n */\n case \"joinsession\":\n\n const joinParticipantPayload: ParticipantPayloadResponse = ParticipantPayloadResponse.fromJSON(message.textBody);\n\n const joiningParticipant: IInternalParticipant = {\n avatar: joinParticipantPayload.avatar,\n displayName: joinParticipantPayload.nickname,\n id: joinParticipantPayload.participantId,\n isHost: joinParticipantPayload.ishost,\n isMuted: joinParticipantPayload.ismuted,\n isUsingTts: joinParticipantPayload.usetts,\n preferredLanguage: joinParticipantPayload.locale,\n };\n\n if (!!this.privConversationServiceConnector.participantJoinCommandReceived) {\n this.privConversationServiceConnector.participantJoinCommandReceived(this.privConversationServiceConnector,\n new ParticipantEventArgs(\n joiningParticipant,\n sessionId));\n }\n\n break;\n\n /**\n * 'LeaveSession' is sent when a user leaves the Conversation'.\n */\n case \"leavesession\":\n\n const leavingParticipant: IInternalParticipant = {\n id: commandPayload.participantId\n };\n\n if (!!this.privConversationServiceConnector.participantLeaveCommandReceived) {\n this.privConversationServiceConnector.participantLeaveCommandReceived(this.privConversationServiceConnector,\n new ParticipantEventArgs(leavingParticipant, sessionId));\n }\n\n break;\n\n /**\n * 'DisconnectSession' is sent when a user is disconnected from the session (e.g. network problem).\n * Check the 'ParticipantId' to check whether the message is for the current user.\n */\n case \"disconnectsession\":\n\n const disconnectParticipant: IInternalParticipant = {\n id: commandPayload.participantId\n };\n\n break;\n\n /**\n * Message not recognized.\n */\n default:\n break;\n }\n break;\n\n /**\n * 'partial' (or 'hypothesis') represents a unfinalized speech message.\n */\n case \"partial\":\n\n /**\n * 'final' (or 'phrase') represents a finalized speech message.\n */\n case \"final\":\n\n const speechPayload: SpeechResponsePayload = SpeechResponsePayload.fromJSON(message.textBody);\n\n const speechResult: ConversationTranslationResult = new ConversationTranslationResult(speechPayload.participantId,\n this.getTranslations(speechPayload.translations),\n speechPayload.language,\n undefined,\n undefined,\n speechPayload.recognition,\n undefined,\n undefined,\n message.textBody,\n undefined);\n\n if (speechPayload.isFinal) {\n // check the length, sometimes empty finals are returned\n if (speechResult.text !== undefined && speechResult.text.length > 0) {\n sendFinal = true;\n } else if (speechPayload.id === this.privLastPartialUtteranceId) {\n // send final as normal. We had a non-empty partial for this same utterance\n // so sending the empty final is important\n sendFinal = true;\n } else {\n // suppress unneeded final\n }\n\n if (sendFinal) {\n if (!!this.privConversationServiceConnector.translationReceived) {\n this.privConversationServiceConnector.translationReceived(this.privConversationServiceConnector,\n new ConversationReceivedTranslationEventArgs(ConversationTranslatorMessageTypes.final, speechResult, sessionId));\n }\n }\n } else if (speechResult.text !== undefined) {\n this.privLastPartialUtteranceId = speechPayload.id;\n if (!!this.privConversationServiceConnector.translationReceived) {\n this.privConversationServiceConnector.translationReceived(this.privConversationServiceConnector,\n new ConversationReceivedTranslationEventArgs(ConversationTranslatorMessageTypes.partial, speechResult, sessionId));\n }\n }\n\n break;\n\n /**\n * \"translated_message\" is a text message or instant message (IM).\n */\n case \"translated_message\":\n\n const textPayload: TextResponsePayload = TextResponsePayload.fromJSON(message.textBody);\n\n const textResult: ConversationTranslationResult = new ConversationTranslationResult(textPayload.participantId,\n this.getTranslations(textPayload.translations),\n textPayload.language,\n undefined,\n undefined,\n textPayload.originalText,\n undefined,\n undefined,\n undefined,\n message.textBody,\n undefined);\n\n if (!!this.privConversationServiceConnector.translationReceived) {\n this.privConversationServiceConnector.translationReceived(this.privConversationServiceConnector,\n new ConversationReceivedTranslationEventArgs(ConversationTranslatorMessageTypes.instantMessage, textResult, sessionId));\n }\n break;\n\n default:\n // ignore any unsupported message types\n break;\n }\n } catch (e) {\n // continue\n }\n return this.receiveConversationMessageOverride();\n });\n }, (error: string) => {\n this.terminateMessageLoop = true;\n });\n\n return communicationCustodian.promise();\n }\n\n private startMessageLoop(): Promise<IConnection> {\n\n this.terminateMessageLoop = false;\n\n const messageRetrievalPromise = this.receiveConversationMessageOverride();\n\n return messageRetrievalPromise.on((r: IConnection) => {\n return true;\n }, (error: string) => {\n this.cancelRecognition(\n this.privRequestSession ? this.privRequestSession.sessionId : \"\",\n this.privRequestSession ? this.privRequestSession.requestId : \"\",\n CancellationReason.Error,\n CancellationErrorCode.RuntimeError,\n error);\n });\n }\n\n // Takes an established websocket connection to the endpoint\n private configConnection(): Promise<IConnection> {\n if (this.privConnectionConfigPromise) {\n if (this.privConnectionConfigPromise.result().isCompleted &&\n (this.privConnectionConfigPromise.result().isError\n || this.privConnectionConfigPromise.result().result.state() === ConnectionState.Disconnected)) {\n\n this.privConnectionConfigPromise = null;\n return this.configConnection();\n } else {\n return this.privConnectionConfigPromise;\n }\n }\n\n if (this.terminateMessageLoop) {\n return PromiseHelper.fromResult<IConnection>(undefined);\n }\n\n this.privConnectionConfigPromise = this.conversationConnectImpl()\n .onSuccessContinueWith((connection: IConnection): any => {\n return connection;\n });\n return this.privConnectionConfigPromise;\n }\n\n private getTranslations(serviceResultTranslations: ITranslationResponsePayload[]): Translations {\n let translations: Translations;\n\n if (undefined !== serviceResultTranslations) {\n translations = new Translations();\n for (const translation of serviceResultTranslations) {\n translations.set(translation.lang, translation.translation);\n }\n }\n\n return translations;\n }\n\n private fetchConversationConnection = (): Promise<IConnection> => {\n return this.configConnection();\n }\n\n}\n"]}