From 17f70415247d54d76ac4bef4615ec96a8db08d58 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Sat, 20 Feb 2021 17:21:52 +0100 Subject: [PATCH] [voicerss] Add support for voices (#10184) Signed-off-by: Laurent Garnier --- .../voicerss/internal/VoiceRSSTTSService.java | 2 +- .../voicerss/internal/VoiceRSSVoice.java | 7 +- .../cloudapi/CachedVoiceRSSCloudImpl.java | 15 ++- .../internal/cloudapi/VoiceRSSCloudAPI.java | 5 +- .../internal/cloudapi/VoiceRSSCloudImpl.java | 100 +++++++++++++++--- .../voice/voicerss/tool/CreateTTSCache.java | 21 ++-- 6 files changed, 118 insertions(+), 32 deletions(-) diff --git a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/VoiceRSSTTSService.java b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/VoiceRSSTTSService.java index a9d9110e5d9..6d5475468e9 100644 --- a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/VoiceRSSTTSService.java +++ b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/VoiceRSSTTSService.java @@ -136,7 +136,7 @@ public class VoiceRSSTTSService implements TTSService { // only a default voice try { File cacheAudioFile = voiceRssImpl.getTextToSpeechAsFile(apiKey, trimmedText, - voice.getLocale().toLanguageTag(), getApiAudioFormat(requestedFormat)); + voice.getLocale().toLanguageTag(), voice.getLabel(), getApiAudioFormat(requestedFormat)); if (cacheAudioFile == null) { throw new TTSException("Could not read from VoiceRSS service"); } diff --git a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/VoiceRSSVoice.java b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/VoiceRSSVoice.java index ef3f8238706..02d33f85025 100644 --- a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/VoiceRSSVoice.java +++ b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/VoiceRSSVoice.java @@ -15,6 +15,7 @@ package org.openhab.voice.voicerss.internal; import java.util.Locale; import org.openhab.core.voice.Voice; +import org.openhab.voice.voicerss.internal.cloudapi.VoiceRSSCloudImpl; /** * Implementation of the Voice interface for VoiceRSS. Label is only "default" @@ -54,7 +55,11 @@ public class VoiceRSSVoice implements Voice { */ @Override public String getUID() { - return "voicerss:" + locale.toLanguageTag().replaceAll("[^a-zA-Z0-9_]", ""); + String uid = "voicerss:" + locale.toLanguageTag().replaceAll("[^a-zA-Z0-9_]", ""); + if (!label.equals(VoiceRSSCloudImpl.DEFAULT_VOICE)) { + uid += "_" + label.replaceAll("[^a-zA-Z0-9_]", ""); + } + return uid; } /** diff --git a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/CachedVoiceRSSCloudImpl.java b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/CachedVoiceRSSCloudImpl.java index 71a16d1ee05..b94f07cf479 100644 --- a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/CachedVoiceRSSCloudImpl.java +++ b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/CachedVoiceRSSCloudImpl.java @@ -55,9 +55,9 @@ public class CachedVoiceRSSCloudImpl extends VoiceRSSCloudImpl { } } - public File getTextToSpeechAsFile(String apiKey, String text, String locale, String audioFormat) + public File getTextToSpeechAsFile(String apiKey, String text, String locale, String voice, String audioFormat) throws IOException { - String fileNameInCache = getUniqueFilenameForText(text, locale); + String fileNameInCache = getUniqueFilenameForText(text, locale, voice); // check if in cache File audioFileInCache = new File(cacheFolder, fileNameInCache + "." + audioFormat.toLowerCase()); if (audioFileInCache.exists()) { @@ -65,7 +65,7 @@ public class CachedVoiceRSSCloudImpl extends VoiceRSSCloudImpl { } // if not in cache, get audio data and put to cache - try (InputStream is = super.getTextToSpeech(apiKey, text, locale, audioFormat); + try (InputStream is = super.getTextToSpeech(apiKey, text, locale, voice, audioFormat); FileOutputStream fos = new FileOutputStream(audioFileInCache)) { copyStream(is, fos); // write text to file for transparency too @@ -89,7 +89,7 @@ public class CachedVoiceRSSCloudImpl extends VoiceRSSCloudImpl { * * Sample: "en-US_00a2653ac5f77063bc4ea2fee87318d3" */ - private String getUniqueFilenameForText(String text, String locale) { + private String getUniqueFilenameForText(String text, String locale, String voice) { try { byte[] bytesOfMessage = text.getBytes(StandardCharsets.UTF_8); MessageDigest md = MessageDigest.getInstance("MD5"); @@ -101,7 +101,12 @@ public class CachedVoiceRSSCloudImpl extends VoiceRSSCloudImpl { while (hashtext.length() < 32) { hashtext = "0" + hashtext; } - return locale + "_" + hashtext; + String filename = locale + "_"; + if (!DEFAULT_VOICE.equals(voice)) { + filename += voice + "_"; + } + filename += hashtext; + return filename; } catch (NoSuchAlgorithmException ex) { // should not happen logger.error("Could not create MD5 hash for '{}'", text, ex); diff --git a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/VoiceRSSCloudAPI.java b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/VoiceRSSCloudAPI.java index 8a7d4b18685..175f8cfa625 100644 --- a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/VoiceRSSCloudAPI.java +++ b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/VoiceRSSCloudAPI.java @@ -68,6 +68,8 @@ public interface VoiceRSSCloudAPI { * the text to translate into speech * @param locale * the locale to use + * @param voice + * the voice to use, "default" for the default voice * @param audioFormat * the audio format to use * @return an InputStream to the audio data in specified format @@ -75,5 +77,6 @@ public interface VoiceRSSCloudAPI { * will be raised if the audio data can not be retrieved from * cloud service */ - InputStream getTextToSpeech(String apiKey, String text, String locale, String audioFormat) throws IOException; + InputStream getTextToSpeech(String apiKey, String text, String locale, String voice, String audioFormat) + throws IOException; } diff --git a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/VoiceRSSCloudImpl.java b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/VoiceRSSCloudImpl.java index 4582d8b48e2..8d50281b963 100644 --- a/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/VoiceRSSCloudImpl.java +++ b/bundles/org.openhab.voice.voicerss/src/main/java/org/openhab/voice/voicerss/internal/cloudapi/VoiceRSSCloudImpl.java @@ -21,10 +21,11 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; -import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.stream.Stream; @@ -34,7 +35,7 @@ import org.slf4j.LoggerFactory; /** * This class implements the Cloud service from VoiceRSS. For more information, - * see API documentation at http://www.voicerss.org/api/documentation.aspx. + * see API documentation at http://www.voicerss.org/api . * * Current state of implementation: *