diff --git a/bundles/org.openhab.core.voice/src/main/java/org/openhab/core/voice/internal/DialogProcessor.java b/bundles/org.openhab.core.voice/src/main/java/org/openhab/core/voice/internal/DialogProcessor.java index 277eb65641..72cef1a493 100644 --- a/bundles/org.openhab.core.voice/src/main/java/org/openhab/core/voice/internal/DialogProcessor.java +++ b/bundles/org.openhab.core.voice/src/main/java/org/openhab/core/voice/internal/DialogProcessor.java @@ -150,6 +150,10 @@ public class DialogProcessor implements KSListener, STTListener { this.ttsFormat = VoiceManagerImpl.getBestMatch(tts.getSupportedFormats(), sink.getSupportedFormats()); } + public void startSingleDialog() { + executeSimpleDialog(); + } + public void start() { KSService ksService = ks; if (ksService != null) { @@ -211,6 +215,10 @@ public class DialogProcessor implements KSListener, STTListener { toggleProcessing(false); } + public boolean isProcessing() { + return processing; + } + private void abortKS() { KSServiceHandle handle = ksServiceHandle; if (handle != null) { @@ -376,4 +384,18 @@ public class DialogProcessor implements KSListener, STTListener { } } } + + /** + * Check if other DialogProcessor instance have same configuration ignoring the keyword spotting configuration + * + * @param dialogProcessor Other DialogProcessor instance + */ + public boolean isCompatible(DialogProcessor dialogProcessor) { + return this.sink.equals(dialogProcessor.sink) && this.source.equals(dialogProcessor.source) + && this.stt.equals(dialogProcessor.stt) && this.tts.equals(dialogProcessor.tts) + && Objects.equals(this.prefVoice, dialogProcessor.prefVoice) + && this.hlis.size() == dialogProcessor.hlis.size() && this.hlis.containsAll(dialogProcessor.hlis) + && this.locale.equals(dialogProcessor.locale) + && Objects.equals(this.listeningItem, dialogProcessor.listeningItem); + } } diff --git a/bundles/org.openhab.core.voice/src/main/java/org/openhab/core/voice/internal/VoiceManagerImpl.java b/bundles/org.openhab.core.voice/src/main/java/org/openhab/core/voice/internal/VoiceManagerImpl.java index 9d9f966991..4797b040eb 100644 --- a/bundles/org.openhab.core.voice/src/main/java/org/openhab/core/voice/internal/VoiceManagerImpl.java +++ b/bundles/org.openhab.core.voice/src/main/java/org/openhab/core/voice/internal/VoiceManagerImpl.java @@ -27,6 +27,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -126,6 +127,7 @@ public class VoiceManagerImpl implements VoiceManager, ConfigOptionProvider { private final Map defaultVoices = new HashMap<>(); private Map dialogProcessors = new HashMap<>(); + private Map singleDialogProcessors = new ConcurrentHashMap<>(); @Activate public VoiceManagerImpl(final @Reference LocaleProvider localeProvider, final @Reference AudioManager audioManager, @@ -544,6 +546,10 @@ public class VoiceManagerImpl implements VoiceManager, ConfigOptionProvider { AudioSource audioSource = (source == null) ? audioManager.getSource() : source; if (audioSource != null) { DialogProcessor processor = dialogProcessors.remove(audioSource.getId()); + singleDialogProcessors.values().removeIf(e -> !e.isProcessing()); + if (processor == null) { + processor = singleDialogProcessors.get(audioSource.getId()); + } if (processor != null) { processor.stop(); logger.debug("Dialog stopped for source {} ({})", audioSource.getLabel(null), audioSource.getId()); @@ -598,13 +604,24 @@ public class VoiceManagerImpl implements VoiceManager, ConfigOptionProvider { throw new IllegalStateException( "Cannot execute a simple dialog as provided locale is not supported by all services."); } else { - DialogProcessor processor = dialogProcessors.get(audioSource.getId()); - if (processor == null) { + boolean isSingleDialog = false; + DialogProcessor activeProcessor = dialogProcessors.get(audioSource.getId()); + singleDialogProcessors.values().removeIf(e -> !e.isProcessing()); + if (activeProcessor == null) { + isSingleDialog = true; + activeProcessor = singleDialogProcessors.get(audioSource.getId()); + } + var processor = new DialogProcessor(sttService, ttsService, prefVoice, interpreters, audioSource, audioSink, + loc, item, this.eventPublisher, this.i18nProvider, b); + if (activeProcessor == null) { logger.debug("Executing a simple dialog for source {} ({})", audioSource.getLabel(null), audioSource.getId()); - processor = new DialogProcessor(sttService, ttsService, prefVoice, interpreters, audioSource, audioSink, - loc, item, this.eventPublisher, this.i18nProvider, b); processor.start(); + singleDialogProcessors.put(audioSource.getId(), processor); + } else if (!isSingleDialog && activeProcessor.isCompatible(processor)) { + logger.debug("Executing a simple dialog for active source {} ({})", audioSource.getLabel(null), + audioSource.getId()); + activeProcessor.startSingleDialog(); } else { throw new IllegalStateException(String.format( "Cannot execute a simple dialog as a dialog is already started for audio source '%s'.",