@hahnpro/ms-speech-sdk
Version:
Microsoft Cognitive Services Speech SDK for JavaScript
1 lines • 54.8 kB
Source Map (JSON)
{"version":3,"sources":["src/common.speech/ServiceRecognizerBase.ts"],"names":[],"mappings":"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","file":"ServiceRecognizerBase.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nimport { ReplayableAudioNode } from \"../common.browser/Exports.js\";\nimport { ConnectionOpenResponse } from \"../common/ConnectionOpenResponse.js\";\nimport {\n ArgumentNullError,\n ConnectionClosedEvent,\n ConnectionEvent,\n ConnectionState,\n createNoDashGuid,\n EventSource,\n IAudioSource,\n IAudioStreamNode,\n IConnection,\n IDisposable,\n IStreamChunk,\n MessageType,\n ServiceEvent,\n Timeout\n} from \"../common/Exports.js\";\nimport { AudioStreamFormatImpl } from \"../sdk/Audio/AudioStreamFormat.js\";\nimport { SpeakerRecognitionModel } from \"../sdk/SpeakerRecognitionModel.js\";\nimport {\n CancellationErrorCode,\n CancellationReason,\n PropertyId,\n RecognitionEventArgs,\n Recognizer,\n SessionEventArgs,\n SpeakerRecognitionResult,\n SpeechRecognitionResult,\n OutputFormat\n} from \"../sdk/Exports.js\";\nimport { Callback } from \"../sdk/Transcription/IConversation.js\";\nimport {\n AgentConfig,\n AutoDetectSourceLanguagesOpenRangeOptionName,\n DynamicGrammarBuilder,\n ISpeechConfigAudioDevice,\n RequestSession,\n SpeechContext,\n SpeechDetected,\n type,\n OutputFormatPropertyName\n} from \"./Exports.js\";\nimport {\n AuthInfo,\n IAuthentication,\n} from \"./IAuthentication.js\";\nimport { IConnectionFactory } from \"./IConnectionFactory.js\";\nimport { RecognizerConfig } from \"./RecognizerConfig.js\";\nimport { SpeechConnectionMessage } from \"./SpeechConnectionMessage.Internal.js\";\nimport { Segmentation, SegmentationMode } from \"./ServiceMessages/PhraseDetection/Segmentation.js\";\nimport { CustomLanguageMappingEntry, PhraseDetectionContext, RecognitionMode } from \"./ServiceMessages/PhraseDetection/PhraseDetectionContext.js\";\nimport { NextAction as NextTranslationAction } from \"./ServiceMessages/Translation/OnSuccess.js\";\nimport { Mode } from \"./ServiceMessages/Translation/InterimResults.js\";\nimport { LanguageIdDetectionMode, LanguageIdDetectionPriority } from \"./ServiceMessages/LanguageId/LanguageIdContext.js\";\nimport { NextAction as NextLangaugeIdAction } from \"./ServiceMessages/LanguageId/OnSuccess.js\";\nimport { OnUnknownAction } from \"./ServiceMessages/LanguageId/OnUnknown.js\";\nimport { ResultType } from \"./ServiceMessages/PhraseOutput/InterimResults.js\";\nimport { PhraseResultOutputType } from \"./ServiceMessages/PhraseOutput/PhraseResults.js\";\nimport { NextAction as NextPhraseDetectionAction } from \"./ServiceMessages/PhraseDetection/OnSuccess.js\";\n\nexport abstract class ServiceRecognizerBase implements IDisposable {\n private privAuthentication: IAuthentication;\n private privConnectionFactory: IConnectionFactory;\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> = undefined;\n private privAuthFetchEventId: string;\n private privIsDisposed: boolean;\n private privMustReportEndOfStream: boolean;\n private privConnectionEvents: EventSource<ConnectionEvent>;\n private privServiceEvents: EventSource<ServiceEvent>;\n private privDynamicGrammar: DynamicGrammarBuilder;\n private privAgentConfig: AgentConfig;\n private privServiceHasSentMessage: boolean;\n private privActivityTemplate: string;\n private privSetTimeout: (cb: () => void, delay: number) => number = setTimeout;\n private privAudioSource: IAudioSource;\n private privIsLiveAudio: boolean = false;\n private privAverageBytesPerMs: number = 0;\n protected privSpeechContext: SpeechContext;\n protected privRequestSession: RequestSession;\n protected privConnectionId: string;\n protected privDiarizationSessionId: string;\n protected privRecognizerConfig: RecognizerConfig;\n protected privRecognizer: Recognizer;\n protected privSuccessCallback: (e: SpeechRecognitionResult) => void;\n protected privErrorCallback: (e: string) => void;\n protected privEnableSpeakerId: boolean = false;\n protected privExpectContentAssessmentResponse: boolean = false;\n\n public constructor(\n authentication: IAuthentication,\n connectionFactory: IConnectionFactory,\n audioSource: IAudioSource,\n recognizerConfig: RecognizerConfig,\n recognizer: Recognizer) {\n\n if (!authentication) {\n throw new ArgumentNullError(\"authentication\");\n }\n\n if (!connectionFactory) {\n throw new ArgumentNullError(\"connectionFactory\");\n }\n\n if (!audioSource) {\n throw new ArgumentNullError(\"audioSource\");\n }\n\n if (!recognizerConfig) {\n throw new ArgumentNullError(\"recognizerConfig\");\n }\n\n this.privEnableSpeakerId = recognizerConfig.isSpeakerDiarizationEnabled;\n this.privMustReportEndOfStream = false;\n this.privAuthentication = authentication;\n this.privConnectionFactory = connectionFactory;\n this.privAudioSource = audioSource;\n this.privRecognizerConfig = recognizerConfig;\n this.privIsDisposed = false;\n this.privRecognizer = recognizer;\n this.privRequestSession = new RequestSession(this.privAudioSource.id());\n this.privConnectionEvents = new EventSource<ConnectionEvent>();\n this.privServiceEvents = new EventSource<ServiceEvent>();\n this.privDynamicGrammar = new DynamicGrammarBuilder();\n this.privSpeechContext = new SpeechContext(this.privDynamicGrammar);\n this.privAgentConfig = new AgentConfig();\n const webWorkerLoadType: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.WebWorkerLoadType, \"on\").toLowerCase();\n if (webWorkerLoadType === \"on\" && typeof (Blob) !== \"undefined\" && typeof (Worker) !== \"undefined\") {\n this.privSetTimeout = Timeout.setTimeout;\n } else {\n if (typeof window !== \"undefined\") {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n this.privSetTimeout = window.setTimeout.bind(window);\n }\n if (typeof globalThis !== \"undefined\") {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n this.privSetTimeout = globalThis.setTimeout.bind(globalThis);\n }\n }\n\n this.connectionEvents.attach((connectionEvent: ConnectionEvent): void => {\n if (connectionEvent.name === \"ConnectionClosedEvent\") {\n const connectionClosedEvent = connectionEvent as ConnectionClosedEvent;\n if (connectionClosedEvent.statusCode === 1003 ||\n connectionClosedEvent.statusCode === 1007 ||\n connectionClosedEvent.statusCode === 1002 ||\n connectionClosedEvent.statusCode === 4000 ||\n this.privRequestSession.numConnectionAttempts > this.privRecognizerConfig.maxRetryCount\n ) {\n void this.cancelRecognitionLocal(CancellationReason.Error,\n connectionClosedEvent.statusCode === 1007 ? CancellationErrorCode.BadRequestParameters : CancellationErrorCode.ConnectionFailure,\n `${connectionClosedEvent.reason} websocket error code: ${connectionClosedEvent.statusCode}`);\n }\n }\n });\n\n if (this.privEnableSpeakerId) {\n this.privDiarizationSessionId = createNoDashGuid();\n }\n }\n\n protected setTranslationJson(): void {\n const targetLanguages: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.SpeechServiceConnection_TranslationToLanguages, undefined);\n if (targetLanguages !== undefined) {\n const languages = targetLanguages.split(\",\");\n const translationVoice: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.SpeechServiceConnection_TranslationVoice, undefined);\n const categoryId: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.SpeechServiceConnection_TranslationCategoryId, undefined);\n\n const action = (translationVoice !== undefined) ? NextTranslationAction.Synthesize : NextTranslationAction.None;\n\n this.privSpeechContext.getContext().translation = {\n onPassthrough: { action }, // Add onPassthrough with same action\n onSuccess: { action },\n output: {\n includePassThroughResults: true, // Explicitly set pass-through results\n interimResults: { mode: Mode.Always }\n },\n targetLanguages: languages,\n };\n\n // Add category if specified\n if (categoryId !== undefined) {\n this.privSpeechContext.getContext().translation.category = categoryId;\n }\n\n if (translationVoice !== undefined) {\n const languageToVoiceMap: { [key: string]: string } = {};\n for (const lang of languages) {\n languageToVoiceMap[lang] = translationVoice;\n }\n this.privSpeechContext.getContext().synthesis = {\n defaultVoices: languageToVoiceMap\n };\n }\n\n // Configure phrase detection for translation\n const phraseDetection = this.privSpeechContext.getContext().phraseDetection || {};\n phraseDetection.onSuccess = { action: NextPhraseDetectionAction.Translate };\n phraseDetection.onInterim = { action: NextPhraseDetectionAction.Translate };\n this.privSpeechContext.getContext().phraseDetection = phraseDetection;\n }\n }\n\n protected setSpeechSegmentationTimeoutJson(): void {\n const speechSegmentationSilenceTimeoutMs: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, undefined);\n const speechSegmentationMaximumTimeMs: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.Speech_SegmentationMaximumTimeMs, undefined);\n const speechSegmentationStrategy: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.Speech_SegmentationStrategy, undefined);\n const segmentation: Segmentation = {\n mode: SegmentationMode.Normal,\n };\n\n let configuredSegment = false;\n\n if (speechSegmentationStrategy !== undefined) {\n configuredSegment = true;\n let segMode: SegmentationMode = SegmentationMode.Normal;\n switch (speechSegmentationStrategy.toLowerCase()) {\n case \"default\":\n break;\n case \"time\":\n segMode = SegmentationMode.Custom;\n break;\n case \"semantic\":\n segMode = SegmentationMode.Semantic;\n break;\n }\n\n segmentation.mode = segMode;\n }\n\n if (speechSegmentationSilenceTimeoutMs !== undefined) {\n configuredSegment = true;\n const segmentationSilenceTimeoutMs: number = parseInt(speechSegmentationSilenceTimeoutMs, 10);\n segmentation.mode = SegmentationMode.Custom;\n segmentation.segmentationSilenceTimeoutMs = segmentationSilenceTimeoutMs;\n }\n\n if (speechSegmentationMaximumTimeMs !== undefined) {\n configuredSegment = true;\n const segmentationMaximumTimeMs: number = parseInt(speechSegmentationMaximumTimeMs, 10);\n segmentation.mode = SegmentationMode.Custom;\n segmentation.segmentationForcedTimeoutMs = segmentationMaximumTimeMs;\n }\n\n if (configuredSegment) {\n const phraseDetection: PhraseDetectionContext = this.privSpeechContext.getContext().phraseDetection || {};\n phraseDetection.mode = this.recognitionMode;\n\n switch (this.recognitionMode) {\n case RecognitionMode.Conversation:\n phraseDetection.conversation = phraseDetection.conversation ?? { segmentation: {} };\n phraseDetection.conversation.segmentation = segmentation;\n\n break;\n case RecognitionMode.Interactive:\n phraseDetection.interactive = phraseDetection.interactive ?? { segmentation: {} };\n phraseDetection.interactive.segmentation = segmentation;\n break;\n case RecognitionMode.Dictation:\n phraseDetection.dictation = phraseDetection.dictation ?? {};\n phraseDetection.dictation.segmentation = segmentation;\n\n break;\n }\n this.privSpeechContext.getContext().phraseDetection = phraseDetection;\n }\n }\n\n protected setLanguageIdJson(): void {\n const phraseDetection: PhraseDetectionContext = this.privSpeechContext.getContext().phraseDetection || {};\n if (this.privRecognizerConfig.autoDetectSourceLanguages !== undefined) {\n const sourceLanguages: string[] = this.privRecognizerConfig.autoDetectSourceLanguages.split(\",\");\n\n if (sourceLanguages.length === 1 && sourceLanguages[0] === AutoDetectSourceLanguagesOpenRangeOptionName) {\n sourceLanguages[0] = \"UND\";\n }\n\n let speechContextLidMode;\n if (this.privRecognizerConfig.languageIdMode === \"Continuous\") {\n speechContextLidMode = LanguageIdDetectionMode.DetectContinuous;\n } else {// recognizerConfig.languageIdMode === \"AtStart\"\n speechContextLidMode = LanguageIdDetectionMode.DetectAtAudioStart;\n }\n\n this.privSpeechContext.getContext().languageId = {\n languages: sourceLanguages,\n mode: speechContextLidMode,\n onSuccess: { action: NextLangaugeIdAction.Recognize },\n onUnknown: { action: OnUnknownAction.None },\n priority: LanguageIdDetectionPriority.PrioritizeLatency\n };\n this.privSpeechContext.getContext().phraseOutput = {\n interimResults: {\n resultType: ResultType.Auto\n },\n phraseResults: {\n resultType: PhraseResultOutputType.Always\n }\n };\n const customModels: CustomLanguageMappingEntry[] = this.privRecognizerConfig.sourceLanguageModels;\n if (customModels !== undefined) {\n phraseDetection.customModels = customModels;\n phraseDetection.onInterim = { action: NextPhraseDetectionAction.None };\n phraseDetection.onSuccess = { action: NextPhraseDetectionAction.None };\n }\n }\n // No longer setting translation-specific configuration here\n // This is now handled in setTranslationJson and setupTranslationWithLanguageId methods\n\n this.privSpeechContext.getContext().phraseDetection = phraseDetection;\n }\n\n protected setOutputDetailLevelJson(): void {\n if (this.privEnableSpeakerId) {\n const requestWordLevelTimestamps: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.SpeechServiceResponse_RequestWordLevelTimestamps, \"false\").toLowerCase();\n if (requestWordLevelTimestamps === \"true\") {\n this.privSpeechContext.setWordLevelTimings();\n } else {\n const outputFormat: string = this.privRecognizerConfig.parameters.getProperty(OutputFormatPropertyName, OutputFormat[OutputFormat.Simple]).toLowerCase();\n if (outputFormat === OutputFormat[OutputFormat.Detailed].toLocaleLowerCase()) {\n this.privSpeechContext.setDetailedOutputFormat();\n }\n }\n }\n }\n\n public get isSpeakerDiarizationEnabled(): boolean {\n return this.privEnableSpeakerId;\n }\n\n public get audioSource(): IAudioSource {\n return this.privAudioSource;\n }\n\n public get speechContext(): SpeechContext {\n return this.privSpeechContext;\n }\n\n public get dynamicGrammar(): DynamicGrammarBuilder {\n return this.privDynamicGrammar;\n }\n\n public get agentConfig(): AgentConfig {\n return this.privAgentConfig;\n }\n\n public set conversationTranslatorToken(token: string) {\n this.privRecognizerConfig.parameters.setProperty(PropertyId.ConversationTranslator_Token, token);\n }\n\n public set voiceProfileType(type: string) {\n this.privRecognizerConfig.parameters.setProperty(PropertyId.SpeechServiceConnection_SpeakerIdMode, type);\n }\n\n public set authentication(auth: IAuthentication) {\n this.privAuthentication = auth;\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.privConnectionPromise !== undefined) {\n try {\n const connection: IConnection = await this.privConnectionPromise;\n await connection.dispose(reason);\n } catch (error) {\n // The connection is in a bad state. But we're trying to kill it, so...\n return;\n }\n }\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 public get recognitionMode(): RecognitionMode {\n return this.privRecognizerConfig.recognitionMode;\n }\n\n protected recognizeOverride: (recoMode: RecognitionMode, sc: (e: SpeechRecognitionResult) => void, ec: (e: string) => void) => Promise<void> = undefined;\n\n public recognizeSpeaker: (model: SpeakerRecognitionModel) => Promise<SpeakerRecognitionResult> = undefined;\n\n public async recognize(\n recoMode: RecognitionMode,\n successCallback: (e: SpeechRecognitionResult) => void,\n errorCallBack: (e: string) => void,\n ): Promise<void> {\n\n if (this.recognizeOverride !== undefined) {\n await this.recognizeOverride(recoMode, successCallback, errorCallBack);\n return;\n }\n // Clear the existing configuration promise to force a re-transmission of config and context.\n this.privConnectionConfigurationPromise = undefined;\n this.privRecognizerConfig.recognitionMode = recoMode;\n\n if (this.privRecognizerConfig.recognitionEndpointVersion === \"2\") {\n const phraseDetection: PhraseDetectionContext = this.privSpeechContext.getContext().phraseDetection || {};\n phraseDetection.mode = recoMode;\n this.privSpeechContext.getContext().phraseDetection = phraseDetection;\n }\n\n // Set language ID (if configured)\n this.setLanguageIdJson();\n\n // Then set translation (if configured)\n this.setTranslationJson();\n\n // Configure the integration between language ID and translation (if both are used)\n if (this.privRecognizerConfig.autoDetectSourceLanguages !== undefined &&\n this.privRecognizerConfig.parameters.getProperty(PropertyId.SpeechServiceConnection_TranslationToLanguages, undefined) !== undefined) {\n this.setupTranslationWithLanguageId();\n }\n\n this.setSpeechSegmentationTimeoutJson();\n this.setOutputDetailLevelJson();\n\n this.privSuccessCallback = successCallback;\n this.privErrorCallback = errorCallBack;\n\n this.privRequestSession.startNewRecognition();\n this.privRequestSession.listenForServiceTelemetry(this.privAudioSource.events);\n\n // Start the connection to the service. The promise this will create is stored and will be used by configureConnection().\n const conPromise: Promise<IConnection> = this.connectImpl();\n let audioNode: ReplayableAudioNode;\n\n try {\n const audioStreamNode: IAudioStreamNode = await this.audioSource.attach(this.privRequestSession.audioNodeId);\n const format: AudioStreamFormatImpl = await this.audioSource.format;\n const deviceInfo: ISpeechConfigAudioDevice = await this.audioSource.deviceInfo;\n this.privIsLiveAudio = deviceInfo.type && deviceInfo.type === type.Microphones;\n\n audioNode = new ReplayableAudioNode(audioStreamNode, format.avgBytesPerSec);\n await this.privRequestSession.onAudioSourceAttachCompleted(audioNode, false);\n this.privRecognizerConfig.SpeechServiceConfig.Context.audio = { source: deviceInfo };\n\n } catch (error) {\n await this.privRequestSession.onStopRecognizing();\n throw error;\n }\n\n try {\n await conPromise;\n } catch (error) {\n await this.cancelRecognitionLocal(CancellationReason.Error, CancellationErrorCode.ConnectionFailure, error as string);\n return;\n }\n\n const sessionStartEventArgs: SessionEventArgs = new SessionEventArgs(this.privRequestSession.sessionId);\n\n if (!!this.privRecognizer.sessionStarted) {\n this.privRecognizer.sessionStarted(this.privRecognizer, sessionStartEventArgs);\n }\n\n void this.receiveMessage();\n const audioSendPromise = this.sendAudio(audioNode);\n\n audioSendPromise.catch(async (error: string): Promise<void> => {\n await this.cancelRecognitionLocal(CancellationReason.Error, CancellationErrorCode.RuntimeError, error);\n });\n\n return;\n }\n\n public async stopRecognizing(): Promise<void> {\n if (this.privRequestSession.isRecognizing) {\n try {\n await this.audioSource.turnOff();\n await this.sendFinalAudio();\n await this.privRequestSession.onStopRecognizing();\n await this.privRequestSession.turnCompletionPromise;\n } finally {\n await this.privRequestSession.dispose();\n }\n }\n return;\n }\n\n public async connect(): Promise<void> {\n await this.connectImpl();\n return Promise.resolve();\n }\n\n public connectAsync(cb?: Callback, err?: Callback): void {\n this.connectImpl().then((): void => {\n try {\n if (!!cb) {\n cb();\n }\n } catch (e) {\n if (!!err) {\n err(e);\n }\n }\n }, (reason: any): void => {\n try {\n if (!!err) {\n err(reason);\n }\n /* eslint-disable no-empty */\n } catch (error) {\n }\n });\n }\n\n protected disconnectOverride: () => Promise<void> = undefined;\n\n public async disconnect(): Promise<void> {\n await this.cancelRecognitionLocal(CancellationReason.Error,\n CancellationErrorCode.NoError,\n \"Disconnecting\");\n\n if (this.disconnectOverride !== undefined) {\n await this.disconnectOverride();\n }\n\n if (this.privConnectionPromise !== undefined) {\n try {\n await (await this.privConnectionPromise).dispose();\n } catch (error) {\n\n }\n }\n this.privConnectionPromise = undefined;\n }\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 // eslint-disable-next-line @typescript-eslint/no-unused-vars\n public sendMessage(message: string): Promise<void> {\n return;\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.privRequestSession.requestId, contentType, payload));\n }\n\n public set activityTemplate(messagePayload: string) {\n this.privActivityTemplate = messagePayload;\n }\n\n public get activityTemplate(): string {\n return this.privActivityTemplate;\n }\n\n public set expectContentAssessmentResponse(value: boolean) {\n this.privExpectContentAssessmentResponse = value;\n }\n\n protected abstract processTypeSpecificMessages(\n connectionMessage: SpeechConnectionMessage,\n successCallback?: (e: SpeechRecognitionResult) => void,\n errorCallBack?: (e: string) => void): Promise<boolean>;\n\n protected async sendTelemetryData(): Promise<void> {\n const telemetryData = this.privRequestSession.getTelemetry();\n if (ServiceRecognizerBase.telemetryDataEnabled !== true ||\n this.privIsDisposed ||\n null === telemetryData) {\n return;\n }\n\n if (!!ServiceRecognizerBase.telemetryData) {\n try {\n ServiceRecognizerBase.telemetryData(telemetryData);\n /* eslint-disable no-empty */\n } catch { }\n }\n\n const connection: IConnection = await this.fetchConnection();\n await connection.send(new SpeechConnectionMessage(\n MessageType.Text,\n \"telemetry\",\n this.privRequestSession.requestId,\n \"application/json\",\n telemetryData));\n }\n\n // Cancels recognition.\n protected abstract cancelRecognition(\n sessionId: string,\n requestId: string,\n cancellationReason: CancellationReason,\n errorCode: CancellationErrorCode,\n error: string): void;\n\n // Cancels recognition.\n protected async cancelRecognitionLocal(\n cancellationReason: CancellationReason,\n errorCode: CancellationErrorCode,\n error: string): Promise<void> {\n\n if (!!this.privRequestSession.isRecognizing) {\n await this.privRequestSession.onStopRecognizing();\n\n this.cancelRecognition(\n this.privRequestSession.sessionId,\n this.privRequestSession.requestId,\n cancellationReason,\n errorCode,\n error);\n }\n }\n\n protected receiveMessageOverride: () => Promise<void> = undefined;\n\n protected async receiveMessage(): Promise<void> {\n try {\n if (this.privIsDisposed) {\n // We're done.\n return;\n }\n\n let connection = await this.fetchConnection();\n const message = await connection.read();\n\n if (this.receiveMessageOverride !== undefined) {\n return this.receiveMessageOverride();\n }\n\n // indicates we are draining the queue and it came with no message;\n if (!message) {\n return this.receiveMessage();\n }\n\n this.privServiceHasSentMessage = true;\n const connectionMessage = SpeechConnectionMessage.fromConnectionMessage(message);\n\n if (connectionMessage.requestId.toLowerCase() === this.privRequestSession.requestId.toLowerCase()) {\n switch (connectionMessage.path.toLowerCase()) {\n case \"turn.start\":\n this.privMustReportEndOfStream = true;\n this.privRequestSession.onServiceTurnStartResponse();\n break;\n\n case \"speech.startdetected\":\n const speechStartDetected: SpeechDetected = SpeechDetected.fromJSON(connectionMessage.textBody, this.privRequestSession.currentTurnAudioOffset);\n const speechStartEventArgs = new RecognitionEventArgs(speechStartDetected.Offset, this.privRequestSession.sessionId);\n if (!!this.privRecognizer.speechStartDetected) {\n this.privRecognizer.speechStartDetected(this.privRecognizer, speechStartEventArgs);\n }\n break;\n\n case \"speech.enddetected\":\n let json: string;\n if (connectionMessage.textBody.length > 0) {\n json = connectionMessage.textBody;\n } else {\n // If the request was empty, the JSON returned is empty.\n json = \"{ Offset: 0 }\";\n }\n const speechStopDetected: SpeechDetected = SpeechDetected.fromJSON(json, this.privRequestSession.currentTurnAudioOffset);\n const speechStopEventArgs = new RecognitionEventArgs(speechStopDetected.Offset + this.privRequestSession.currentTurnAudioOffset, this.privRequestSession.sessionId);\n if (!!this.privRecognizer.speechEndDetected) {\n this.privRecognizer.speechEndDetected(this.privRecognizer, speechStopEventArgs);\n }\n break;\n\n case \"turn.end\":\n await this.sendTelemetryData();\n if (this.privRequestSession.isSpeechEnded && this.privMustReportEndOfStream) {\n this.privMustReportEndOfStream = false;\n await this.cancelRecognitionLocal(CancellationReason.EndOfStream, CancellationErrorCode.NoError, undefined);\n }\n const sessionStopEventArgs: SessionEventArgs = new SessionEventArgs(this.privRequestSession.sessionId);\n await this.privRequestSession.onServiceTurnEndResponse(this.privRecognizerConfig.isContinuousRecognition);\n if (!this.privRecognizerConfig.isContinuousRecognition || this.privRequestSession.isSpeechEnded || !this.privRequestSession.isRecognizing) {\n if (!!this.privRecognizer.sessionStopped) {\n this.privRecognizer.sessionStopped(this.privRecognizer, sessionStopEventArgs);\n }\n return;\n } else {\n connection = await this.fetchConnection();\n await this.sendPrePayloadJSON(connection);\n }\n break;\n\n default:\n if (!await 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 return this.receiveMessage();\n } catch (error) {\n return null;\n }\n }\n\n private updateSpeakerDiarizationAudioOffset(): void {\n const bytesSent: number = this.privRequestSession.recognitionBytesSent;\n const audioOffsetMs: number = this.privAverageBytesPerMs !== 0 ? bytesSent / this.privAverageBytesPerMs : 0;\n this.privSpeechContext.setSpeakerDiarizationAudioOffsetMs(audioOffsetMs);\n }\n\n protected sendSpeechContext(connection: IConnection, generateNewRequestId: boolean): Promise<void> {\n if (this.privEnableSpeakerId) {\n this.updateSpeakerDiarizationAudioOffset();\n }\n\n const speechContextJson = this.speechContext.toJSON();\n if (generateNewRequestId) {\n this.privRequestSession.onSpeechContext();\n }\n\n if (speechContextJson) {\n return connection.send(new SpeechConnectionMessage(\n MessageType.Text,\n \"speech.context\",\n this.privRequestSession.requestId,\n \"application/json\",\n speechContextJson));\n }\n return;\n }\n\n protected sendPrePayloadJSONOverride: (connection: IConnection) => Promise<void> = undefined;\n\n protected setupTranslationWithLanguageId(): void {\n const targetLanguages: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.SpeechServiceConnection_TranslationToLanguages, undefined);\n const hasLanguageId = this.privRecognizerConfig.autoDetectSourceLanguages !== undefined;\n\n if (targetLanguages !== undefined && hasLanguageId) {\n // Configure phraseOutput for translation + language ID scenario\n this.privSpeechContext.getContext().phraseOutput = {\n interimResults: {\n resultType: ResultType.None\n },\n phraseResults: {\n resultType: PhraseResultOutputType.None\n }\n };\n\n // Handle custom language models and voice mapping\n const translationContext = this.privSpeechContext.getContext().translation;\n if (translationContext) {\n const customModels = this.privRecognizerConfig.sourceLanguageModels;\n if (customModels !== undefined && customModels.length > 0) {\n const phraseDetection = this.privSpeechContext.getContext().phraseDetection || {};\n phraseDetection.customModels = customModels;\n this.privSpeechContext.getContext().phraseDetection = phraseDetection;\n }\n\n const translationVoice = this.privRecognizerConfig.parameters.getProperty(\n PropertyId.SpeechServiceConnection_TranslationVoice, undefined);\n\n if (translationVoice !== undefined) {\n // Update translation actions for synthesis\n translationContext.onSuccess = { action: NextTranslationAction.Synthesize };\n translationContext.onPassthrough = { action: NextTranslationAction.Synthesize };\n }\n }\n }\n }\n\n protected noOp(): Promise<void> {\n // operation not supported\n return;\n }\n\n // Encapsulated for derived service recognizers that need to send additional JSON\n protected async sendPrePayloadJSON(connection: IConnection, generateNewRequestId: boolean = true): Promise<void> {\n if (this.sendPrePayloadJSONOverride !== undefined) {\n return this.sendPrePayloadJSONOverride(connection);\n }\n\n await this.sendSpeechContext(connection, generateNewRequestId);\n await this.sendWaveHeader(connection);\n return;\n }\n\n protected async sendWaveHeader(connection: IConnection): Promise<void> {\n const format: AudioStreamFormatImpl = await this.audioSource.format;\n // this.writeBufferToConsole(format.header);\n return connection.send(new SpeechConnectionMessage(\n MessageType.Binary,\n \"audio\",\n this.privRequestSession.requestId,\n \"audio/x-wav\",\n format.header\n ));\n }\n\n protected postConnectImplOverride: (connection: Promise<IConnection>) => Promise<IConnection> = undefined;\n\n // Establishes a websocket connection to the end point.\n protected connectImpl(): Promise<IConnection> {\n if (this.privConnectionPromise !== undefined) {\n return this.privConnectionPromise.then((connection: IConnection): Promise<IConnection> => {\n if (connection.state() === ConnectionState.Disconnected) {\n this.privConnectionId = null;\n this.privConnectionPromise = undefined;\n this.privServiceHasSentMessage = false;\n return this.connectImpl();\n }\n return this.privConnectionPromise;\n }, (): Promise<IConnection> => {\n this.privConnectionId = null;\n this.privConnectionPromise = undefined;\n this.privServiceHasSentMessage = false;\n return this.connectImpl();\n });\n }\n\n this.privConnectionPromise = this.retryableConnect();\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 if (this.postConnectImplOverride !== undefined) {\n return this.postConnectImplOverride(this.privConnectionPromise);\n }\n\n return this.privConnectionPromise;\n }\n\n protected configConnectionOverride: (connection: IConnection) => Promise<IConnection> = undefined;\n protected handleSpeechPhraseMessage: (textBody: string) => Promise<void> = undefined;\n protected handleSpeechHypothesisMessage: (textBody: string) => void = undefined;\n\n protected sendSpeechServiceConfig(connection: IConnection, requestSession: RequestSession, SpeechServiceConfigJson: string): Promise<void> {\n requestSession.onSpeechContext();\n // filter out anything that is not required for the service to work.\n if (ServiceRecognizerBase.telemetryDataEnabled !== true) {\n const withTelemetry: { context: { system: string } } = JSON.parse(SpeechServiceConfigJson) as { context: { system: string } };\n\n const replacement: any = {\n context: {\n system: withTelemetry.context.system,\n },\n };\n\n SpeechServiceConfigJson = JSON.stringify(replacement);\n }\n\n if (this.privRecognizerConfig.parameters.getProperty(\"f0f5debc-f8c9-4892-ac4b-90a7ab359fd2\", \"false\").toLowerCase() === \"true\") {\n const json: { context: { DisableReferenceChannel: string; MicSpec: string } } = JSON.parse(SpeechServiceConfigJson) as { context: { DisableReferenceChannel: string; MicSpec: string } };\n json.context.DisableReferenceChannel = \"True\";\n json.context.MicSpec = \"1_0_0\";\n SpeechServiceConfigJson = JSON.stringify(json);\n }\n\n if (SpeechServiceConfigJson) {\n return connection.send(new SpeechConnectionMessage(\n MessageType.Text,\n \"speech.config\",\n requestSession.requestId,\n \"application/json\",\n SpeechServiceConfigJson));\n }\n\n return;\n }\n\n protected 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 this.privServiceHasSentMessage = false;\n return this.fetchConnection();\n }\n return this.privConnectionConfigurationPromise;\n }, (): Promise<IConnection> => {\n this.privConnectionId = null;\n this.privConnectionConfigurationPromise = undefined;\n this.privServiceHasSentMessage = false;\n return this.fetchConnection();\n });\n }\n\n this.privConnectionConfigurationPromise = this.configureConnection();\n return await this.privConnectionConfigurationPromise;\n }\n\n protected async sendAudio(audioStreamNode: IAudioStreamNode): Promise<void> {\n const audioFormat: AudioStreamFormatImpl = await this.audioSource.format;\n this.privAverageBytesPerMs = audioFormat.avgBytesPerSec / 1000;\n // The time we last sent data to the service.\n let nextSendTime: number = Date.now();\n\n // Max amount to send before we start to throttle\n const fastLaneSizeMs: string = this.privRecognizerConfig.parameters.getProperty(\"SPEECH-TransmitLengthBeforThrottleMs\", \"5000\");\n const maxSendUnthrottledBytes: number = audioFormat.avgBytesPerSec / 1000 * parseInt(fastLaneSizeMs, 10);\n const startRecogNumber: number = this.privRequestSession.recogNumber;\n\n const readAndUploadCycle = async (): Promise<void> => {\n // If speech is done, stop sending audio.\n if (!this.privIsDisposed &&\n !this.privRequestSession.isSpeechEnded &&\n this.privRequestSession.isRecognizing &&\n this.privRequestSession.recogNumber === startRecogNumber) {\n\n const connection: IConnection = await this.fetchConnection();\n const audioStreamChunk: IStreamChunk<ArrayBuffer> = await audioStreamNode.read();\n // we have a new audio chunk to upload.\n if (this.privRequestSession.isSpeechEnded) {\n // If service already recognized audio end then don't send any more audio\n return;\n }\n\n let payload: ArrayBuffer;\n let sendDelay: number;\n\n if (!audioStreamChunk || audioStreamChunk.isEnd) {\n payload = null;\n sendDelay = 0;\n } else {\n payload = audioStreamChunk.buffer;\n\n this.privRequestSession.onAudioSent(payload.byteLength);\n\n if (maxSendUnthrottledBytes >= this.privRequestSession.bytesSent) {\n sendDelay = 0;\n } else {\n sendDelay = Math.max(0, nextSendTime - Date.now());\n }\n }\n\n if (0 !== sendDelay) {\n await this.delay(sendDelay);\n }\n\n if (payload !== null) {\n nextSendTime = Date.now() + (payload.byteLength * 1000 / (audioFormat.avgBytesPerSec * 2));\n }\n\n // Are we still alive?\n if (!this.privIsDisposed &&\n !this.privRequestSession.isSpeechEnded &&\n this.privRequestSession.isRecognizing &&\n this.privRequestSession.recogNumber === startRecogNumber) {\n connection.send(\n new SpeechConnectionMessage(MessageType.Binary, \"audio\", this.privRequestSession.requestId, null, payload)\n ).catch((): void => {\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n this.privRequestSession.onServiceTurnEndResponse(this.privRecognizerConfig.isContinuousRecognition).catch((): void => { });\n });\n\n if (!audioStreamChunk?.isEnd) {\n // this.writeBufferToConsole(payload);\n // Regardless of success or failure, schedule the next upload.\n // If the underlying connection was broken, the next cycle will\n // get a new connection and re-transmit missing audio automatically.\n return readAndUploadCycle();\n } else {\n // the audio stream has been closed, no need to schedule next\n // read-upload cycle.\n if (!this.privIsLiveAudio) {\n this.privRequestSession.onSpeechEnde