{"version":3,"sources":["src/common.speech/Transcription/ConversationServiceAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,EAIH,YAAY,EACZ,WAAW,EAEd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACH,qBAAqB,EACrB,kBAAkB,EAMrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEH,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EACxB,MAAM,eAAe,CAAC;AAgBvB,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AAYzF;;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,CAAmC;IACtE,OAAO,CAAC,kBAAkB,CAAgB;IAC1C,OAAO,CAAC,oBAAoB,CAAU;IACtC,OAAO,CAAC,0BAA0B,CAAS;IAC3C,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;IAIf,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3C,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7D,SAAS,CAAC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;cAezB,2BAA2B,IAAI,OAAO,CAAC,OAAO,CAAC;IAK/D,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;;OAEG;cACa,uBAAuB,CAAC,UAAU,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAK/F;;OAEG;YACW,kCAAkC;YA0VlC,gBAAgB;IAkB9B,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,eAAe;CAY1B","file":"ConversationServiceAdapter.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT license.\r\n\r\nimport {\r\n    ConnectionState,\r\n    createNoDashGuid,\r\n    Deferred,\r\n    IAudioSource,\r\n    IConnection,\r\n    MessageType,\r\n} from \"../../common/Exports.js\";\r\nimport {\r\n    CancellationErrorCode,\r\n    CancellationReason,\r\n    ConversationExpirationEventArgs,\r\n    ConversationTranslationCanceledEventArgs,\r\n    ConversationTranslationResult,\r\n    ResultReason,\r\n    Translations\r\n} from \"../../sdk/Exports.js\";\r\nimport {\r\n    CognitiveTokenAuthentication,\r\n    IAuthentication,\r\n    IConnectionFactory,\r\n    RecognizerConfig,\r\n    ServiceRecognizerBase\r\n} from \"../Exports.js\";\r\nimport { ConversationConnectionMessage } from \"./ConversationConnectionMessage.js\";\r\nimport { ConversationRequestSession } from \"./ConversationRequestSession.js\";\r\nimport {\r\n    ConversationReceivedTranslationEventArgs,\r\n    LockRoomEventArgs,\r\n    MuteAllEventArgs,\r\n    ParticipantAttributeEventArgs,\r\n    ParticipantEventArgs,\r\n    ParticipantsListEventArgs\r\n} from \"./ConversationTranslatorEventArgs.js\";\r\nimport {\r\n    ConversationTranslatorCommandTypes,\r\n    ConversationTranslatorMessageTypes,\r\n    IInternalParticipant\r\n} from \"./ConversationTranslatorInterfaces.js\";\r\nimport { ConversationTranslatorRecognizer } from \"./ConversationTranslatorRecognizer.js\";\r\nimport {\r\n    CommandResponsePayload,\r\n    IParticipantPayloadResponse,\r\n    IParticipantsListPayloadResponse,\r\n    ITranslationResponsePayload,\r\n    ParticipantPayloadResponse,\r\n    ParticipantsListPayloadResponse,\r\n    SpeechResponsePayload,\r\n    TextResponsePayload\r\n} from \"./ServiceMessages/Exports.js\";\r\n\r\n/**\r\n * The service adapter handles sending and receiving messages to the Conversation Translator websocket.\r\n */\r\nexport class ConversationServiceAdapter extends ServiceRecognizerBase {\r\n    private privConversationServiceConnector: ConversationTranslatorRecognizer;\r\n    private privConversationConnectionFactory: IConnectionFactory;\r\n    private privConversationAuthFetchEventId: string;\r\n    private privConversationAuthentication: IAuthentication;\r\n    private privConversationRequestSession: ConversationRequestSession;\r\n    private privConnectionConfigPromise: Promise<IConnection> = undefined;\r\n    private privConnectionLoop: Promise<void>;\r\n    private terminateMessageLoop: boolean;\r\n    private privLastPartialUtteranceId: string;\r\n    private privConversationIsDisposed: boolean;\r\n\r\n    public constructor(\r\n        authentication: IAuthentication,\r\n        connectionFactory: IConnectionFactory,\r\n        audioSource: IAudioSource,\r\n        recognizerConfig: RecognizerConfig,\r\n        conversationServiceConnector: ConversationTranslatorRecognizer) {\r\n\r\n        super(authentication, connectionFactory, audioSource, recognizerConfig, conversationServiceConnector);\r\n\r\n        this.privLastPartialUtteranceId = \"\";\r\n        this.privConversationServiceConnector = conversationServiceConnector;\r\n        this.privConversationAuthentication = authentication;\r\n        this.receiveMessageOverride = (): Promise<void> => this.receiveConversationMessageOverride();\r\n        this.recognizeOverride = (): Promise<void> => this.noOp();\r\n        this.postConnectImplOverride = (connection: Promise<IConnection>): Promise<IConnection> => this.conversationConnectImpl(connection);\r\n        this.configConnectionOverride = (): Promise<IConnection> => this.configConnection();\r\n        this.disconnectOverride = (): Promise<void> => this.privDisconnect();\r\n        this.privConversationRequestSession = new ConversationRequestSession(createNoDashGuid());\r\n        this.privConversationConnectionFactory = connectionFactory;\r\n        this.privConversationIsDisposed = false;\r\n    }\r\n\r\n    public isDisposed(): boolean {\r\n        return super.isDisposed() || this.privConversationIsDisposed;\r\n    }\r\n\r\n    public async dispose(reason?: string): Promise<void> {\r\n        this.privConversationIsDisposed = true;\r\n        if (this.privConnectionConfigPromise !== undefined) {\r\n            const connection: IConnection = await this.privConnectionConfigPromise;\r\n            await connection.dispose(reason);\r\n        }\r\n        await super.dispose(reason);\r\n    }\r\n\r\n    public async sendMessage(message: string): Promise<void> {\r\n        const connection: IConnection = await this.fetchConnection();\r\n        return connection.send(new ConversationConnectionMessage(\r\n            MessageType.Text,\r\n            message));\r\n    }\r\n\r\n    public async sendMessageAsync(message: string): Promise<void> {\r\n        const connection: IConnection = await this.fetchConnection();\r\n\r\n        await connection.send(new ConversationConnectionMessage(MessageType.Text, message));\r\n    }\r\n\r\n    protected privDisconnect(): Promise<void> {\r\n        if (this.terminateMessageLoop) {\r\n            return;\r\n        }\r\n        this.cancelRecognition(this.privConversationRequestSession.sessionId,\r\n            this.privConversationRequestSession.requestId,\r\n            CancellationReason.Error,\r\n            CancellationErrorCode.NoError,\r\n            \"Disconnecting\");\r\n\r\n        this.terminateMessageLoop = true;\r\n        return Promise.resolve();\r\n    }\r\n\r\n    // eslint-disable-next-line @typescript-eslint/require-await\r\n    protected async processTypeSpecificMessages(): Promise<boolean> {\r\n        return true;\r\n    }\r\n\r\n    // Cancels recognition.\r\n    protected cancelRecognition(\r\n        sessionId: string,\r\n        requestId: string,\r\n        cancellationReason: CancellationReason,\r\n        errorCode: CancellationErrorCode,\r\n        error: string): void {\r\n\r\n        this.terminateMessageLoop = true;\r\n\r\n        const cancelEvent: ConversationTranslationCanceledEventArgs = new ConversationTranslationCanceledEventArgs(\r\n            cancellationReason,\r\n            error,\r\n            errorCode,\r\n            undefined,\r\n            sessionId);\r\n\r\n        try {\r\n            if (!!this.privConversationServiceConnector.canceled) {\r\n                this.privConversationServiceConnector.canceled(this.privConversationServiceConnector, cancelEvent);\r\n            }\r\n        } catch {\r\n            // continue on error\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Establishes a websocket connection to the end point.\r\n     */\r\n    protected async conversationConnectImpl(connection: Promise<IConnection>): Promise<IConnection> {\r\n        this.privConnectionLoop = this.startMessageLoop();\r\n        return connection;\r\n    }\r\n\r\n    /**\r\n     * Process incoming websocket messages\r\n     */\r\n    private async receiveConversationMessageOverride(): Promise<void> {\r\n        if (this.isDisposed() || this.terminateMessageLoop) {\r\n            return Promise.resolve();\r\n        }\r\n        // we won't rely on the cascading promises of the connection since we want to continually be available to receive messages\r\n        const communicationCustodian: Deferred<void> = new Deferred<void>();\r\n\r\n        try {\r\n            const connection: IConnection = await this.fetchConnection();\r\n            const message: ConversationConnectionMessage = await connection.read() as ConversationConnectionMessage;\r\n            if (this.isDisposed() || this.terminateMessageLoop) {\r\n                // We're done.\r\n                communicationCustodian.resolve();\r\n                return Promise.resolve();\r\n            }\r\n\r\n            if (!message) {\r\n                return this.receiveConversationMessageOverride();\r\n            }\r\n\r\n            const sessionId: string = this.privConversationRequestSession.sessionId;\r\n            const conversationMessageType: string = message.conversationMessageType.toLowerCase();\r\n            let sendFinal: boolean = false;\r\n\r\n            try {\r\n                switch (conversationMessageType) {\r\n                    case \"info\":\r\n                    case \"participant_command\":\r\n                    case \"command\":\r\n                        const commandPayload: CommandResponsePayload = CommandResponsePayload.fromJSON(message.textBody);\r\n                        switch (commandPayload.command.toLowerCase()) {\r\n\r\n                            /**\r\n                             * 'ParticpantList' is the first message sent to the user after the websocket connection has opened.\r\n                             * The consuming client must wait for this message to arrive\r\n                             * before starting to send their own data.\r\n                             */\r\n                            case \"participantlist\":\r\n\r\n                                const participantsPayload: IParticipantsListPayloadResponse = ParticipantsListPayloadResponse.fromJSON(message.textBody);\r\n\r\n                                const participantsResult: IInternalParticipant[] = participantsPayload.participants.map((p: IParticipantPayloadResponse): IInternalParticipant => {\r\n                                    const participant: IInternalParticipant = {\r\n                                        avatar: p.avatar,\r\n                                        displayName: p.nickname,\r\n                                        id: p.participantId,\r\n                                        isHost: p.ishost,\r\n                                        isMuted: p.ismuted,\r\n                                        isUsingTts: p.usetts,\r\n                                        preferredLanguage: p.locale\r\n                                    };\r\n                                    return participant;\r\n                                });\r\n\r\n                                if (!!this.privConversationServiceConnector.participantsListReceived) {\r\n                                    this.privConversationServiceConnector.participantsListReceived(this.privConversationServiceConnector,\r\n                                        new ParticipantsListEventArgs(participantsPayload.roomid, participantsPayload.token,\r\n                                            participantsPayload.translateTo, participantsPayload.profanityFilter,\r\n                                            participantsPayload.roomProfanityFilter, participantsPayload.roomLocked,\r\n                                            participantsPayload.muteAll, participantsResult, sessionId));\r\n                                }\r\n                                break;\r\n\r\n                            /**\r\n                             * 'SetTranslateToLanguages' represents the list of languages being used in the Conversation by all users(?).\r\n                             * This is sent at the start of the Conversation\r\n                             */\r\n                            case \"settranslatetolanguages\":\r\n\r\n                                if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\r\n                                    this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\r\n                                        new ParticipantAttributeEventArgs(commandPayload.participantId,\r\n                                            ConversationTranslatorCommandTypes.setTranslateToLanguages,\r\n                                            commandPayload.value, sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'SetProfanityFiltering' lets the client set the level of profanity filtering.\r\n                             * If sent by the participant the setting will effect only their own profanity level.\r\n                             * If sent by the host, the setting will effect all participants including the host.\r\n                             * Note: the profanity filters differ from Speech Service (?): 'marked', 'raw', 'removed', 'tagged'\r\n                             */\r\n                            case \"setprofanityfiltering\":\r\n\r\n                                if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\r\n                                    this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\r\n                                        new ParticipantAttributeEventArgs(commandPayload.participantId,\r\n                                            ConversationTranslatorCommandTypes.setProfanityFiltering,\r\n                                            commandPayload.value, sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'SetMute' is sent if the participant has been muted by the host.\r\n                             * Check the 'participantId' to determine if the current user has been muted.\r\n                             */\r\n                            case \"setmute\":\r\n\r\n                                if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\r\n                                    this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\r\n                                        new ParticipantAttributeEventArgs(commandPayload.participantId,\r\n                                            ConversationTranslatorCommandTypes.setMute,\r\n                                            commandPayload.value, sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'SetMuteAll' is sent if the Conversation has been muted by the host.\r\n                             */\r\n                            case \"setmuteall\":\r\n\r\n                                if (!!this.privConversationServiceConnector.muteAllCommandReceived) {\r\n                                    this.privConversationServiceConnector.muteAllCommandReceived(this.privConversationServiceConnector,\r\n                                        new MuteAllEventArgs(commandPayload.value as boolean, sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'RoomExpirationWarning' is sent towards the end of the Conversation session to give a timeout warning.\r\n                             */\r\n                            case \"roomexpirationwarning\":\r\n\r\n                                if (!!this.privConversationServiceConnector.conversationExpiration) {\r\n                                    this.privConversationServiceConnector.conversationExpiration(this.privConversationServiceConnector,\r\n                                        new ConversationExpirationEventArgs(commandPayload.value as number, this.privConversationRequestSession.sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'SetUseTts' is sent as a confirmation if the user requests TTS to be turned on or off.\r\n                             */\r\n                            case \"setusetts\":\r\n\r\n                                if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\r\n                                    this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\r\n                                        new ParticipantAttributeEventArgs(commandPayload.participantId,\r\n                                            ConversationTranslatorCommandTypes.setUseTTS,\r\n                                            commandPayload.value, sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'SetLockState' is set if the host has locked or unlocked the Conversation.\r\n                             */\r\n                            case \"setlockstate\":\r\n\r\n                                if (!!this.privConversationServiceConnector.lockRoomCommandReceived) {\r\n                                    this.privConversationServiceConnector.lockRoomCommandReceived(this.privConversationServiceConnector,\r\n                                        new LockRoomEventArgs(commandPayload.value as boolean, sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'ChangeNickname' is received if a user changes their display name.\r\n                             * Any cached particpiants list should be updated to reflect the display name.\r\n                             */\r\n                            case \"changenickname\":\r\n\r\n                                if (!!this.privConversationServiceConnector.participantUpdateCommandReceived) {\r\n                                    this.privConversationServiceConnector.participantUpdateCommandReceived(this.privConversationServiceConnector,\r\n                                        new ParticipantAttributeEventArgs(commandPayload.participantId,\r\n                                            ConversationTranslatorCommandTypes.changeNickname,\r\n                                            commandPayload.value, sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'JoinSession' is sent when a user joins the Conversation.\r\n                             */\r\n                            case \"joinsession\":\r\n\r\n                                const joinParticipantPayload: ParticipantPayloadResponse = ParticipantPayloadResponse.fromJSON(message.textBody);\r\n\r\n                                const joiningParticipant: IInternalParticipant = {\r\n                                    avatar: joinParticipantPayload.avatar,\r\n                                    displayName: joinParticipantPayload.nickname,\r\n                                    id: joinParticipantPayload.participantId,\r\n                                    isHost: joinParticipantPayload.ishost,\r\n                                    isMuted: joinParticipantPayload.ismuted,\r\n                                    isUsingTts: joinParticipantPayload.usetts,\r\n                                    preferredLanguage: joinParticipantPayload.locale,\r\n                                };\r\n\r\n                                if (!!this.privConversationServiceConnector.participantJoinCommandReceived) {\r\n                                    this.privConversationServiceConnector.participantJoinCommandReceived(this.privConversationServiceConnector,\r\n                                        new ParticipantEventArgs(\r\n                                            joiningParticipant,\r\n                                            sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'LeaveSession' is sent when a user leaves the Conversation'.\r\n                             */\r\n                            case \"leavesession\":\r\n\r\n                                const leavingParticipant: IInternalParticipant = {\r\n                                    id: commandPayload.participantId\r\n                                };\r\n\r\n                                if (!!this.privConversationServiceConnector.participantLeaveCommandReceived) {\r\n                                    this.privConversationServiceConnector.participantLeaveCommandReceived(this.privConversationServiceConnector,\r\n                                        new ParticipantEventArgs(leavingParticipant, sessionId));\r\n                                }\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * 'DisconnectSession' is sent when a user is disconnected from the session (e.g. network problem).\r\n                             * Check the 'ParticipantId' to check whether the message is for the current user.\r\n                             */\r\n                            case \"disconnectsession\":\r\n\r\n                                // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n                                const disconnectParticipant: IInternalParticipant = {\r\n                                    id: commandPayload.participantId\r\n                                };\r\n\r\n                                break;\r\n\r\n                            case \"token\":\r\n                                const token = new CognitiveTokenAuthentication(\r\n                                    (): Promise<string> => {\r\n                                        const authorizationToken = commandPayload.token;\r\n                                        return Promise.resolve(authorizationToken);\r\n                                    },\r\n                                    (): Promise<string> => {\r\n                                        const authorizationToken = commandPayload.token;\r\n                                        return Promise.resolve(authorizationToken);\r\n                                    });\r\n                                this.authentication = token;\r\n                                this.privConversationServiceConnector.onToken(token);\r\n\r\n                                break;\r\n\r\n                            /**\r\n                             * Message not recognized.\r\n                             */\r\n                            default:\r\n                                break;\r\n                        }\r\n                        break;\r\n\r\n                    /**\r\n                     * 'partial' (or 'hypothesis') represents a unfinalized speech message.\r\n                     */\r\n                    case \"partial\":\r\n\r\n                    /**\r\n                     * 'final' (or 'phrase') represents a finalized speech message.\r\n                     */\r\n                    case \"final\":\r\n\r\n                        const speechPayload: SpeechResponsePayload = SpeechResponsePayload.fromJSON(message.textBody);\r\n                        const conversationResultReason: ResultReason = (conversationMessageType === \"final\") ? ResultReason.TranslatedParticipantSpeech : ResultReason.TranslatingParticipantSpeech;\r\n\r\n                        const speechResult: ConversationTranslationResult = new ConversationTranslationResult(speechPayload.participantId,\r\n                            this.getTranslations(speechPayload.translations),\r\n                            speechPayload.language,\r\n                            speechPayload.id,\r\n                            conversationResultReason,\r\n                            speechPayload.recognition,\r\n                            undefined,\r\n                            undefined,\r\n                            message.textBody,\r\n                            undefined);\r\n\r\n                        if (speechPayload.isFinal) {\r\n                            // check the length, sometimes empty finals are returned\r\n                            if (speechResult.text !== undefined && speechResult.text.length > 0) {\r\n                                sendFinal = true;\r\n                            } else if (speechPayload.id === this.privLastPartialUtteranceId) {\r\n                                // send final as normal. We had a non-empty partial for this same utterance\r\n                                // so sending the empty final is important\r\n                                sendFinal = true;\r\n                            } else {\r\n                                // suppress unneeded final\r\n                            }\r\n\r\n                            if (sendFinal) {\r\n                                if (!!this.privConversationServiceConnector.translationReceived) {\r\n                                    this.privConversationServiceConnector.translationReceived(this.privConversationServiceConnector,\r\n                                        new ConversationReceivedTranslationEventArgs(ConversationTranslatorMessageTypes.final, speechResult, sessionId));\r\n                                }\r\n                            }\r\n                        } else if (speechResult.text !== undefined) {\r\n                            this.privLastPartialUtteranceId = speechPayload.id;\r\n                            if (!!this.privConversationServiceConnector.translationReceived) {\r\n                                this.privConversationServiceConnector.translationReceived(this.privConversationServiceConnector,\r\n                                    new ConversationReceivedTranslationEventArgs(ConversationTranslatorMessageTypes.partial, speechResult, sessionId));\r\n                            }\r\n                        }\r\n\r\n                        break;\r\n\r\n                    /**\r\n                     * \"translated_message\" is a text message or instant message (IM).\r\n                     */\r\n                    case \"translated_message\":\r\n\r\n                        const textPayload: TextResponsePayload = TextResponsePayload.fromJSON(message.textBody);\r\n                        // TODO: (Native parity) a result reason should be set based whether the participantId is ours or not\r\n\r\n                        const textResult: ConversationTranslationResult = new ConversationTranslationResult(textPayload.participantId,\r\n                            this.getTranslations(textPayload.translations),\r\n                            textPayload.language,\r\n                            undefined,\r\n                            undefined,\r\n                            textPayload.originalText,\r\n                            undefined,\r\n                            undefined,\r\n                            undefined,\r\n                            message.textBody,\r\n                            undefined);\r\n\r\n                        if (!!this.privConversationServiceConnector.translationReceived) {\r\n                            this.privConversationServiceConnector.translationReceived(this.privConversationServiceConnector,\r\n                                new ConversationReceivedTranslationEventArgs(ConversationTranslatorMessageTypes.instantMessage, textResult, sessionId));\r\n                        }\r\n                        break;\r\n\r\n                    default:\r\n                        // ignore any unsupported message types\r\n                        break;\r\n                }\r\n            } catch (e) {\r\n                // continue\r\n            }\r\n            return this.receiveConversationMessageOverride();\r\n        } catch (e) {\r\n            this.terminateMessageLoop = true;\r\n        }\r\n\r\n        return communicationCustodian.promise;\r\n    }\r\n\r\n    private async startMessageLoop(): Promise<void> {\r\n        if (this.isDisposed()) {\r\n            return Promise.resolve();\r\n        }\r\n        this.terminateMessageLoop = false;\r\n\r\n        const messageRetrievalPromise = this.receiveConversationMessageOverride();\r\n\r\n        try {\r\n            const r = await messageRetrievalPromise;\r\n            return r;\r\n        } catch (error) {\r\n            this.cancelRecognition(this.privRequestSession ? this.privRequestSession.sessionId : \"\", this.privRequestSession ? this.privRequestSession.requestId : \"\", CancellationReason.Error, CancellationErrorCode.RuntimeError, error as string);\r\n            return null;\r\n        }\r\n    }\r\n\r\n    // Takes an established websocket connection to the endpoint\r\n    private configConnection(): Promise<IConnection> {\r\n        if (this.isDisposed()) {\r\n            return Promise.resolve<IConnection>(undefined);\r\n        }\r\n        if (this.privConnectionConfigPromise !== undefined) {\r\n            return this.privConnectionConfigPromise.then((connection: IConnection): Promise<IConnection> => {\r\n                if (connection.state() === ConnectionState.Disconnected) {\r\n                    this.privConnectionId = null;\r\n                    this.privConnectionConfigPromise = undefined;\r\n                    return this.configConnection();\r\n                }\r\n                return this.privConnectionConfigPromise;\r\n            }, (): Promise<IConnection> => {\r\n                this.privConnectionId = null;\r\n                this.privConnectionConfigPromise = undefined;\r\n                return this.configConnection();\r\n            });\r\n        }\r\n        if (this.terminateMessageLoop) {\r\n            return Promise.resolve<IConnection>(undefined);\r\n        }\r\n\r\n        this.privConnectionConfigPromise = this.connectImpl().then((connection: IConnection): IConnection => connection);\r\n\r\n        return this.privConnectionConfigPromise;\r\n    }\r\n\r\n    private getTranslations(serviceResultTranslations: ITranslationResponsePayload[]): Translations {\r\n        let translations: Translations;\r\n\r\n        if (undefined !== serviceResultTranslations) {\r\n            translations = new Translations();\r\n            for (const translation of serviceResultTranslations) {\r\n                translations.set(translation.lang, translation.translation);\r\n            }\r\n        }\r\n\r\n        return translations;\r\n    }\r\n}\r\n"]}