[googletts] Improve exception handling (#11925)
* Improve exception handling * Moved classes to dto package to reduce SAT warning Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
parent
76855fd81a
commit
0936d97b41
|
@ -1,34 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.voice.googletts.internal;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown, if an authentication error is given.
|
|
||||||
*
|
|
||||||
* @author Christoph Weitkamp - Initial contribution
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@NonNullByDefault
|
|
||||||
public class AuthenticationException extends Exception {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public AuthenticationException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthenticationException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Dictionary;
|
import java.util.Dictionary;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -37,21 +36,23 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.MimeTypes;
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
import org.openhab.core.audio.AudioFormat;
|
import org.openhab.core.audio.AudioFormat;
|
||||||
|
import org.openhab.core.auth.AuthenticationException;
|
||||||
import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
|
import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
|
||||||
import org.openhab.core.auth.client.oauth2.OAuthClientService;
|
import org.openhab.core.auth.client.oauth2.OAuthClientService;
|
||||||
import org.openhab.core.auth.client.oauth2.OAuthException;
|
import org.openhab.core.auth.client.oauth2.OAuthException;
|
||||||
import org.openhab.core.auth.client.oauth2.OAuthFactory;
|
import org.openhab.core.auth.client.oauth2.OAuthFactory;
|
||||||
import org.openhab.core.auth.client.oauth2.OAuthResponseException;
|
import org.openhab.core.auth.client.oauth2.OAuthResponseException;
|
||||||
|
import org.openhab.core.i18n.CommunicationException;
|
||||||
import org.openhab.core.io.net.http.HttpRequestBuilder;
|
import org.openhab.core.io.net.http.HttpRequestBuilder;
|
||||||
import org.openhab.voice.googletts.internal.protocol.AudioConfig;
|
import org.openhab.voice.googletts.internal.dto.AudioConfig;
|
||||||
import org.openhab.voice.googletts.internal.protocol.AudioEncoding;
|
import org.openhab.voice.googletts.internal.dto.AudioEncoding;
|
||||||
import org.openhab.voice.googletts.internal.protocol.ListVoicesResponse;
|
import org.openhab.voice.googletts.internal.dto.ListVoicesResponse;
|
||||||
import org.openhab.voice.googletts.internal.protocol.SsmlVoiceGender;
|
import org.openhab.voice.googletts.internal.dto.SsmlVoiceGender;
|
||||||
import org.openhab.voice.googletts.internal.protocol.SynthesisInput;
|
import org.openhab.voice.googletts.internal.dto.SynthesisInput;
|
||||||
import org.openhab.voice.googletts.internal.protocol.SynthesizeSpeechRequest;
|
import org.openhab.voice.googletts.internal.dto.SynthesizeSpeechRequest;
|
||||||
import org.openhab.voice.googletts.internal.protocol.SynthesizeSpeechResponse;
|
import org.openhab.voice.googletts.internal.dto.SynthesizeSpeechResponse;
|
||||||
import org.openhab.voice.googletts.internal.protocol.Voice;
|
import org.openhab.voice.googletts.internal.dto.Voice;
|
||||||
import org.openhab.voice.googletts.internal.protocol.VoiceSelectionParams;
|
import org.openhab.voice.googletts.internal.dto.VoiceSelectionParams;
|
||||||
import org.osgi.service.cm.Configuration;
|
import org.osgi.service.cm.Configuration;
|
||||||
import org.osgi.service.cm.ConfigurationAdmin;
|
import org.osgi.service.cm.ConfigurationAdmin;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -59,6 +60,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Google Cloud TTS API call implementation.
|
* Google Cloud TTS API call implementation.
|
||||||
|
@ -152,8 +154,8 @@ class GoogleCloudAPI {
|
||||||
getAccessToken();
|
getAccessToken();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
initVoices();
|
initVoices();
|
||||||
} catch (AuthenticationException | IOException ex) {
|
} catch (AuthenticationException | CommunicationException e) {
|
||||||
logger.warn("Error initializing Google Cloud TTS service: {}", ex.getMessage());
|
logger.warn("Error initializing Google Cloud TTS service: {}", e.getMessage());
|
||||||
oAuthService = null;
|
oAuthService = null;
|
||||||
initialized = false;
|
initialized = false;
|
||||||
voices.clear();
|
voices.clear();
|
||||||
|
@ -177,17 +179,24 @@ class GoogleCloudAPI {
|
||||||
/**
|
/**
|
||||||
* Fetches the OAuth2 tokens from Google Cloud Platform if the auth-code is set in the configuration. If successful
|
* Fetches the OAuth2 tokens from Google Cloud Platform if the auth-code is set in the configuration. If successful
|
||||||
* the auth-code will be removed from the configuration.
|
* the auth-code will be removed from the configuration.
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException
|
||||||
|
* @throws CommunicationException
|
||||||
*/
|
*/
|
||||||
private void getAccessToken() throws AuthenticationException, IOException {
|
@SuppressWarnings("null")
|
||||||
|
private void getAccessToken() throws AuthenticationException, CommunicationException {
|
||||||
String authcode = config.authcode;
|
String authcode = config.authcode;
|
||||||
if (authcode != null && !authcode.isEmpty()) {
|
if (authcode != null && !authcode.isEmpty()) {
|
||||||
logger.debug("Trying to get access and refresh tokens.");
|
logger.debug("Trying to get access and refresh tokens.");
|
||||||
try {
|
try {
|
||||||
oAuthService.getAccessTokenResponseByAuthorizationCode(authcode, GCP_REDIRECT_URI);
|
oAuthService.getAccessTokenResponseByAuthorizationCode(authcode, GCP_REDIRECT_URI);
|
||||||
} catch (OAuthException | OAuthResponseException ex) {
|
} catch (OAuthException | OAuthResponseException e) {
|
||||||
logger.debug("Error fetching access token: {}", ex.getMessage(), ex);
|
logger.debug("Error fetching access token: {}", e.getMessage(), e);
|
||||||
throw new AuthenticationException(
|
throw new AuthenticationException(
|
||||||
"Error fetching access token. Invalid authcode? Please generate a new one.");
|
"Error fetching access token. Invalid authcode? Please generate a new one.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommunicationException(
|
||||||
|
String.format("An unexpected IOException occurred: %s", e.getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
config.authcode = null;
|
config.authcode = null;
|
||||||
|
@ -207,14 +216,17 @@ class GoogleCloudAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAuthorizationHeader() throws AuthenticationException, IOException {
|
@SuppressWarnings("null")
|
||||||
|
private String getAuthorizationHeader() throws AuthenticationException, CommunicationException {
|
||||||
final AccessTokenResponse accessTokenResponse;
|
final AccessTokenResponse accessTokenResponse;
|
||||||
try {
|
try {
|
||||||
accessTokenResponse = oAuthService.getAccessTokenResponse();
|
accessTokenResponse = oAuthService.getAccessTokenResponse();
|
||||||
} catch (OAuthException | OAuthResponseException ex) {
|
} catch (OAuthException | OAuthResponseException e) {
|
||||||
logger.debug("Error fetching access token: {}", ex.getMessage(), ex);
|
logger.debug("Error fetching access token: {}", e.getMessage(), e);
|
||||||
throw new AuthenticationException(
|
throw new AuthenticationException(
|
||||||
"Error fetching access token. Invalid authcode? Please generate a new one.");
|
"Error fetching access token. Invalid authcode? Please generate a new one.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommunicationException(String.format("An unexpected IOException occurred: %s", e.getMessage()));
|
||||||
}
|
}
|
||||||
if (accessTokenResponse == null || accessTokenResponse.getAccessToken() == null
|
if (accessTokenResponse == null || accessTokenResponse.getAccessToken() == null
|
||||||
|| accessTokenResponse.getAccessToken().isEmpty()) {
|
|| accessTokenResponse.getAccessToken().isEmpty()) {
|
||||||
|
@ -255,13 +267,16 @@ class GoogleCloudAPI {
|
||||||
*/
|
*/
|
||||||
Set<GoogleTTSVoice> getVoicesForLocale(Locale locale) {
|
Set<GoogleTTSVoice> getVoicesForLocale(Locale locale) {
|
||||||
Set<GoogleTTSVoice> localeVoices = voices.get(locale);
|
Set<GoogleTTSVoice> localeVoices = voices.get(locale);
|
||||||
return localeVoices != null ? localeVoices : Collections.emptySet();
|
return localeVoices != null ? localeVoices : Set.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Google API call to load locales and voices.
|
* Google API call to load locales and voices.
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException
|
||||||
|
* @throws CommunicationException
|
||||||
*/
|
*/
|
||||||
private void initVoices() throws AuthenticationException, IOException {
|
private void initVoices() throws AuthenticationException, CommunicationException {
|
||||||
if (oAuthService != null) {
|
if (oAuthService != null) {
|
||||||
voices.clear();
|
voices.clear();
|
||||||
for (GoogleTTSVoice voice : listVoices()) {
|
for (GoogleTTSVoice voice : listVoices()) {
|
||||||
|
@ -281,25 +296,32 @@ class GoogleCloudAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
private List<GoogleTTSVoice> listVoices() throws AuthenticationException, IOException {
|
private List<GoogleTTSVoice> listVoices() throws AuthenticationException, CommunicationException {
|
||||||
HttpRequestBuilder builder = HttpRequestBuilder.getFrom(LIST_VOICES_URL)
|
HttpRequestBuilder builder = HttpRequestBuilder.getFrom(LIST_VOICES_URL)
|
||||||
.withHeader(HttpHeader.AUTHORIZATION.name(), getAuthorizationHeader());
|
.withHeader(HttpHeader.AUTHORIZATION.name(), getAuthorizationHeader());
|
||||||
|
|
||||||
ListVoicesResponse listVoicesResponse = gson.fromJson(builder.getContentAsString(), ListVoicesResponse.class);
|
try {
|
||||||
|
ListVoicesResponse listVoicesResponse = gson.fromJson(builder.getContentAsString(),
|
||||||
|
ListVoicesResponse.class);
|
||||||
|
|
||||||
if (listVoicesResponse == null || listVoicesResponse.getVoices() == null) {
|
if (listVoicesResponse == null || listVoicesResponse.getVoices() == null) {
|
||||||
return Collections.emptyList();
|
return List.of();
|
||||||
}
|
|
||||||
|
|
||||||
List<GoogleTTSVoice> result = new ArrayList<>();
|
|
||||||
for (Voice voice : listVoicesResponse.getVoices()) {
|
|
||||||
for (String languageCode : voice.getLanguageCodes()) {
|
|
||||||
result.add(new GoogleTTSVoice(Locale.forLanguageTag(languageCode), voice.getName(),
|
|
||||||
voice.getSsmlGender().name()));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
List<GoogleTTSVoice> result = new ArrayList<>();
|
||||||
|
for (Voice voice : listVoicesResponse.getVoices()) {
|
||||||
|
for (String languageCode : voice.getLanguageCodes()) {
|
||||||
|
result.add(new GoogleTTSVoice(Locale.forLanguageTag(languageCode), voice.getName(),
|
||||||
|
voice.getSsmlGender().name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
// do nothing
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommunicationException(String.format("An unexpected IOException occurred: %s", e.getMessage()));
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -319,7 +341,7 @@ class GoogleCloudAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] synthesizeSpeech(String text, GoogleTTSVoice voice, String codec) {
|
public byte[] synthesizeSpeech(String text, GoogleTTSVoice voice, String codec) {
|
||||||
String[] format = getFormatForCodec(codec);
|
String[] format = getFormatForCodec(codec);
|
||||||
String fileNameInCache = getUniqueFilenameForText(text, voice.getTechnicalName());
|
String fileNameInCache = getUniqueFilenameForText(text, voice.getTechnicalName());
|
||||||
File audioFileInCache = new File(cacheFolder, fileNameInCache + "." + format[1]);
|
File audioFileInCache = new File(cacheFolder, fileNameInCache + "." + format[1]);
|
||||||
|
@ -336,19 +358,17 @@ class GoogleCloudAPI {
|
||||||
saveAudioAndTextToFile(text, audioFileInCache, audio, voice.getTechnicalName());
|
saveAudioAndTextToFile(text, audioFileInCache, audio, voice.getTechnicalName());
|
||||||
}
|
}
|
||||||
return audio;
|
return audio;
|
||||||
} catch (AuthenticationException ex) {
|
} catch (AuthenticationException | CommunicationException e) {
|
||||||
logger.warn("Error initializing Google Cloud TTS service: {}", ex.getMessage());
|
logger.warn("Error initializing Google Cloud TTS service: {}", e.getMessage());
|
||||||
oAuthService = null;
|
oAuthService = null;
|
||||||
initialized = false;
|
initialized = false;
|
||||||
voices.clear();
|
voices.clear();
|
||||||
return null;
|
} catch (FileNotFoundException e) {
|
||||||
} catch (FileNotFoundException ex) {
|
logger.warn("Could not write file {} to cache: {}", audioFileInCache, e.getMessage());
|
||||||
logger.warn("Could not write {} to cache", audioFileInCache, ex);
|
} catch (IOException e) {
|
||||||
return null;
|
logger.debug("An unexpected IOException occurred: {}", e.getMessage());
|
||||||
} catch (IOException ex) {
|
|
||||||
logger.error("Could not write {} to cache", audioFileInCache, ex);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,10 +378,11 @@ class GoogleCloudAPI {
|
||||||
* @param cacheFile Cache entry file.
|
* @param cacheFile Cache entry file.
|
||||||
* @param audio Byte array of the audio.
|
* @param audio Byte array of the audio.
|
||||||
* @param voiceName Used voice
|
* @param voiceName Used voice
|
||||||
|
* @throws FileNotFoundException
|
||||||
* @throws IOException in case of file handling exceptions
|
* @throws IOException in case of file handling exceptions
|
||||||
*/
|
*/
|
||||||
private void saveAudioAndTextToFile(String text, File cacheFile, byte[] audio, String voiceName)
|
private void saveAudioAndTextToFile(String text, File cacheFile, byte[] audio, String voiceName)
|
||||||
throws IOException {
|
throws IOException, FileNotFoundException {
|
||||||
logger.debug("Caching audio file {}", cacheFile.getName());
|
logger.debug("Caching audio file {}", cacheFile.getName());
|
||||||
try (FileOutputStream audioFileOutputStream = new FileOutputStream(cacheFile)) {
|
try (FileOutputStream audioFileOutputStream = new FileOutputStream(cacheFile)) {
|
||||||
audioFileOutputStream.write(audio);
|
audioFileOutputStream.write(audio);
|
||||||
|
@ -405,10 +426,12 @@ class GoogleCloudAPI {
|
||||||
* @param voice Voice parameter
|
* @param voice Voice parameter
|
||||||
* @param audioFormat Audio encoding format
|
* @param audioFormat Audio encoding format
|
||||||
* @return Audio input stream or {@code null} when encoding exceptions occur
|
* @return Audio input stream or {@code null} when encoding exceptions occur
|
||||||
|
* @throws AuthenticationException
|
||||||
|
* @throws CommunicationException
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "null", "unused" })
|
@SuppressWarnings("null")
|
||||||
private byte[] synthesizeSpeechByGoogle(String text, GoogleTTSVoice voice, String audioFormat)
|
private byte[] synthesizeSpeechByGoogle(String text, GoogleTTSVoice voice, String audioFormat)
|
||||||
throws AuthenticationException, IOException {
|
throws AuthenticationException, CommunicationException {
|
||||||
AudioConfig audioConfig = new AudioConfig(AudioEncoding.valueOf(audioFormat), config.pitch, config.speakingRate,
|
AudioConfig audioConfig = new AudioConfig(AudioEncoding.valueOf(audioFormat), config.pitch, config.speakingRate,
|
||||||
config.volumeGainDb);
|
config.volumeGainDb);
|
||||||
SynthesisInput synthesisInput = new SynthesisInput(text);
|
SynthesisInput synthesisInput = new SynthesisInput(text);
|
||||||
|
@ -422,15 +445,22 @@ class GoogleCloudAPI {
|
||||||
.withHeader(HttpHeader.AUTHORIZATION.name(), getAuthorizationHeader())
|
.withHeader(HttpHeader.AUTHORIZATION.name(), getAuthorizationHeader())
|
||||||
.withContent(gson.toJson(request), MimeTypes.Type.APPLICATION_JSON.name());
|
.withContent(gson.toJson(request), MimeTypes.Type.APPLICATION_JSON.name());
|
||||||
|
|
||||||
SynthesizeSpeechResponse synthesizeSpeechResponse = gson.fromJson(builder.getContentAsString(),
|
try {
|
||||||
SynthesizeSpeechResponse.class);
|
SynthesizeSpeechResponse synthesizeSpeechResponse = gson.fromJson(builder.getContentAsString(),
|
||||||
|
SynthesizeSpeechResponse.class);
|
||||||
|
|
||||||
if (synthesizeSpeechResponse == null) {
|
if (synthesizeSpeechResponse == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] encodedBytes = synthesizeSpeechResponse.getAudioContent().getBytes(StandardCharsets.UTF_8);
|
||||||
|
return Base64.getDecoder().decode(encodedBytes);
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
// do nothing
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommunicationException(String.format("An unexpected IOException occurred: %s", e.getMessage()));
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
byte[] encodedBytes = synthesizeSpeechResponse.getAudioContent().getBytes(StandardCharsets.UTF_8);
|
|
||||||
return Base64.getDecoder().decode(encodedBytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -445,9 +475,9 @@ class GoogleCloudAPI {
|
||||||
byte[] bytesOfMessage = (config.toConfigString() + text).getBytes(StandardCharsets.UTF_8);
|
byte[] bytesOfMessage = (config.toConfigString() + text).getBytes(StandardCharsets.UTF_8);
|
||||||
String fileNameHash = String.format("%032x", new BigInteger(1, md.digest(bytesOfMessage)));
|
String fileNameHash = String.format("%032x", new BigInteger(1, md.digest(bytesOfMessage)));
|
||||||
return voiceName + "_" + fileNameHash;
|
return voiceName + "_" + fileNameHash;
|
||||||
} catch (NoSuchAlgorithmException ex) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
// should not happen
|
// should not happen
|
||||||
logger.error("Could not create MD5 hash for '{}'", text, ex);
|
logger.error("Could not create MD5 hash for '{}'", text, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import org.openhab.core.config.core.ConfigurableService;
|
||||||
import org.openhab.core.voice.TTSException;
|
import org.openhab.core.voice.TTSException;
|
||||||
import org.openhab.core.voice.TTSService;
|
import org.openhab.core.voice.TTSService;
|
||||||
import org.openhab.core.voice.Voice;
|
import org.openhab.core.voice.Voice;
|
||||||
import org.openhab.voice.googletts.internal.protocol.AudioEncoding;
|
import org.openhab.voice.googletts.internal.dto.AudioEncoding;
|
||||||
import org.osgi.framework.Constants;
|
import org.osgi.framework.Constants;
|
||||||
import org.osgi.service.cm.ConfigurationAdmin;
|
import org.osgi.service.cm.ConfigurationAdmin;
|
||||||
import org.osgi.service.component.annotations.Activate;
|
import org.osgi.service.component.annotations.Activate;
|
||||||
|
@ -330,7 +330,7 @@ public class GoogleTTSService implements TTSService {
|
||||||
// create the audio byte array for given text, locale, format
|
// create the audio byte array for given text, locale, format
|
||||||
byte[] audio = apiImpl.synthesizeSpeech(trimmedText, (GoogleTTSVoice) voice, requestedFormat.getCodec());
|
byte[] audio = apiImpl.synthesizeSpeech(trimmedText, (GoogleTTSVoice) voice, requestedFormat.getCodec());
|
||||||
if (audio == null) {
|
if (audio == null) {
|
||||||
throw new TTSException("Could not read from Google Cloud TTS Service");
|
throw new TTSException("Could not synthesize text via Google Cloud TTS Service");
|
||||||
}
|
}
|
||||||
return new ByteArrayAudioStream(audio, requestedFormat);
|
return new ByteArrayAudioStream(audio, requestedFormat);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import java.util.Locale;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.voice.Voice;
|
import org.openhab.core.voice.Voice;
|
||||||
import org.openhab.voice.googletts.internal.protocol.SsmlVoiceGender;
|
import org.openhab.voice.googletts.internal.dto.SsmlVoiceGender;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the Voice interface for Google Cloud TTS Service.
|
* Implementation of the Voice interface for Google Cloud TTS Service.
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The configuration of the synthesized audio.
|
* The configuration of the synthesized audio.
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration to set up audio encoder.
|
* Configuration to set up audio encoder.
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gender of the voice as described in SSML voice element.
|
* Gender of the voice as described in SSML voice element.
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains text input to be synthesized. Either text or ssml must be supplied. Supplying both or neither returns
|
* Contains text input to be synthesized. Either text or ssml must be supplied. Supplying both or neither returns
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synthesizes speech synchronously: receive results after all text input has been processed.
|
* Synthesizes speech synchronously: receive results after all text input has been processed.
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message returned to the client by the text.synthesize method.
|
* The message returned to the client by the text.synthesize method.
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.voice.googletts.internal.protocol;
|
package org.openhab.voice.googletts.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description of which voice to use for a synthesis request.
|
* Description of which voice to use for a synthesis request.
|
Loading…
Reference in New Issue