in src/common.speech/DialogServiceAdapter.ts [379:513]
private receiveDialogMessageOverride(): Promise<void> {
// we won't rely on the cascading promises of the connection since we want to continually be available to receive messages
const communicationCustodian: Deferred<void> = new Deferred<void>();
const loop = async (): Promise<void> => {
try {
const isDisposed: boolean = this.isDisposed();
const terminateMessageLoop = (!this.isDisposed() && this.terminateMessageLoop);
if (isDisposed || terminateMessageLoop) {
// We're done.
communicationCustodian.resolve(undefined);
return;
}
const connection: IConnection = await this.fetchConnection();
const message: ConnectionMessage = await connection.read();
if (!message) {
return loop();
}
const connectionMessage = SpeechConnectionMessage.fromConnectionMessage(message);
switch (connectionMessage.path.toLowerCase()) {
case "turn.start":
{
const turnRequestId = connectionMessage.requestId.toUpperCase();
const audioSessionReqId = this.privRequestSession.requestId.toUpperCase();
// turn started by the service
if (turnRequestId !== audioSessionReqId) {
this.privTurnStateManager.StartTurn(turnRequestId);
} else {
this.privRequestSession.onServiceTurnStartResponse();
}
}
break;
case "speech.startdetected":
const speechStartDetected: SpeechDetected = SpeechDetected.fromJSON(connectionMessage.textBody);
const speechStartEventArgs = new RecognitionEventArgs(speechStartDetected.Offset, this.privRequestSession.sessionId);
if (!!this.privRecognizer.speechStartDetected) {
this.privRecognizer.speechStartDetected(this.privRecognizer, speechStartEventArgs);
}
break;
case "speech.enddetected":
let json: string;
if (connectionMessage.textBody.length > 0) {
json = connectionMessage.textBody;
} else {
// If the request was empty, the JSON returned is empty.
json = "{ Offset: 0 }";
}
const speechStopDetected: SpeechDetected = SpeechDetected.fromJSON(json);
this.privRequestSession.onServiceRecognized(speechStopDetected.Offset + this.privRequestSession.currentTurnAudioOffset);
const speechStopEventArgs = new RecognitionEventArgs(speechStopDetected.Offset + this.privRequestSession.currentTurnAudioOffset, this.privRequestSession.sessionId);
if (!!this.privRecognizer.speechEndDetected) {
this.privRecognizer.speechEndDetected(this.privRecognizer, speechStopEventArgs);
}
break;
case "turn.end":
{
const turnEndRequestId = connectionMessage.requestId.toUpperCase();
const audioSessionReqId = this.privRequestSession.requestId.toUpperCase();
// turn started by the service
if (turnEndRequestId !== audioSessionReqId) {
this.privTurnStateManager.CompleteTurn(turnEndRequestId);
} else {
// Audio session turn
const sessionStopEventArgs: SessionEventArgs = new SessionEventArgs(this.privRequestSession.sessionId);
await this.privRequestSession.onServiceTurnEndResponse(false);
if (!this.privRecognizerConfig.isContinuousRecognition || this.privRequestSession.isSpeechEnded || !this.privRequestSession.isRecognizing) {
if (!!this.privRecognizer.sessionStopped) {
this.privRecognizer.sessionStopped(this.privRecognizer, sessionStopEventArgs);
}
}
// report result to promise.
if (!!this.privSuccessCallback && this.privLastResult) {
try {
this.privSuccessCallback(this.privLastResult);
this.privLastResult = null;
} catch (e) {
if (!!this.privErrorCallback) {
this.privErrorCallback(e);
}
}
// Only invoke the call back once.
// and if it's successful don't invoke the
// error after that.
this.privSuccessCallback = undefined;
this.privErrorCallback = undefined;
}
}
}
break;
default:
if (!this.processTypeSpecificMessages(connectionMessage)) {
if (!!this.serviceEvents) {
this.serviceEvents.onEvent(new ServiceEvent(connectionMessage.path.toLowerCase(), connectionMessage.textBody));
}
}
}
const ret: Promise<void> = loop();
return ret;
} catch (error) {
this.terminateMessageLoop = true;
communicationCustodian.resolve();
}
};
loop().catch((reason: string): void => {
Events.instance.onEvent(new BackgroundEvent(reason));
});
return communicationCustodian.promise;
}