diff --git a/Unreal/Plugins/AvatarCore_STT/Source/AvatarCore_STT/Private/Processor/Azure/STTProcessorAzure.cpp b/Unreal/Plugins/AvatarCore_STT/Source/AvatarCore_STT/Private/Processor/Azure/STTProcessorAzure.cpp index 4393dbe..1aa5cc8 100644 --- a/Unreal/Plugins/AvatarCore_STT/Source/AvatarCore_STT/Private/Processor/Azure/STTProcessorAzure.cpp +++ b/Unreal/Plugins/AvatarCore_STT/Source/AvatarCore_STT/Private/Processor/Azure/STTProcessorAzure.cpp @@ -73,7 +73,7 @@ void USTTProcessorAzure::OnChunkReceived(TArray PCMData, FAudioInformatio if (IsValid(STTManager) && STTManager->IsBlocked()) return; - if (!AzureRunnable) //Runable not ready + if (!AzureRunnable || !bTranscriptionRunning) //Runable not ready or previous session ended { USTTProcessorAzure::StartRecognition(); } @@ -99,20 +99,25 @@ void USTTProcessorAzure::OnSpeechStateChanged(ESTTTalkingState TalkingState) StopRecognition(true); } else if (TalkingState == ESTTTalkingState::SILENCE || TalkingState == ESTTTalkingState::TRANSCRIBING) { - if (AzureRunnable) - StopRecognition(false); - else { - if (!intermediateResult.IsEmpty()) { - USTTProcessorBase::OnTranscriptionResult(TranscriptionCounter, intermediateResult, DetectedLanguage); - intermediateResult = ""; - } + if (AzureRunnable) { + StopRecognition(false); // Signal stop, runnable delivers final result via OnRecognized/OnRunnableEnded + } + else if (!intermediateResult.IsEmpty()) { + // No runnable pending, send accumulated result immediately + USTTProcessorBase::OnTranscriptionResult(TranscriptionCounter, intermediateResult, DetectedLanguage); + intermediateResult = ""; } } } void USTTProcessorAzure::StartRecognition() { - StopRecognition(true); //In case there is something else running + StopRecognition(true); //In case there is something else running + // Force-destroy any leftover runnable from a non-forced stop + if (AzureRunnable) { + AzureRunnable->StopRecognition(true); + AzureRunnable = nullptr; + } intermediateResult = ""; USTTProcessorBase::OnTranscriptionStarted(); AzureRunnable = MakeUnique(config, audioConfig, STTManager->GetSpecialWords(), this, false); @@ -120,14 +125,14 @@ void USTTProcessorAzure::StartRecognition() void USTTProcessorAzure::StopRecognition(bool Forced) { - if (!bTranscriptionRunning) - return; - bTranscriptionRunning = false; if (AzureRunnable) { AzureRunnable->StopRecognition(Forced); - AzureRunnable = nullptr; + if (Forced) { + AzureRunnable = nullptr; // Immediate cleanup, no result expected + } + // Non-forced: runnable finishes gracefully and delivers final result if(bDebugMode && STTManager!=nullptr) STTManager->OnSTTLog.Broadcast(TEXT("Recognition thread stopped.")); } @@ -135,7 +140,11 @@ void USTTProcessorAzure::StopRecognition(bool Forced) void USTTProcessorAzure::OnRecognizing(const FString& RecognizedText) { - if (IsValid(STTManager) && STTManager->IsBlocked()) + if (!bTranscriptionRunning) + return; + if (!IsValid(STTManager)) + return; + if (STTManager->IsBlocked()) return; FString tmpResult; @@ -149,7 +158,9 @@ void USTTProcessorAzure::OnRecognizing(const FString& RecognizedText) void USTTProcessorAzure::OnRecognized(const FString& RecognizedText, const FString& Language) { - if (IsValid(STTManager) && STTManager->IsBlocked()) + if (!IsValid(STTManager)) + return; + if (STTManager->IsBlocked()) return; this->DetectedLanguage = Language; @@ -178,22 +189,32 @@ void USTTProcessorAzure::OnConnectionSuccess() void USTTProcessorAzure::OnRunnableEnded() { bTranscriptionRunning = false; + AzureRunnable = nullptr; - if (!intermediateResult.IsEmpty()) { - STTManager->OnTranscriptionReceived.Broadcast(TranscriptionCounter, *intermediateResult, this->DetectedLanguage); - intermediateResult.Empty(); + if (IsValid(STTManager)) { + // Send any remaining intermediate result that wasn't finalized by OnRecognized + if (!intermediateResult.IsEmpty()) { + USTTProcessorBase::OnTranscriptionResult(TranscriptionCounter, intermediateResult, DetectedLanguage); + intermediateResult.Empty(); + } + else { + // Ensure we return to SILENCE even if no result was produced + // (empty audio, network timeout, etc.) to prevent stuck TRANSCRIBING state + STTManager->UserSpeechStateChanged(ESTTTalkingState::SILENCE); + } } - - AzureRunnable = nullptr; } void USTTProcessorAzure::OnAzureError(FString Error) { - if (IsValid(STTManager)) - STTManager->OnSTTError.Broadcast(Error); - bTranscriptionRunning = false; AzureRunnable = nullptr; + intermediateResult.Empty(); + + if (IsValid(STTManager)) { + STTManager->OnSTTError.Broadcast(Error); + STTManager->UserSpeechStateChanged(ESTTTalkingState::SILENCE); + } } FString USTTProcessorAzure::AzureEnumToString(EAzureLanguages Language)