From fee9c85f493d7566cdba6049a78f6a91e8f26e34 Mon Sep 17 00:00:00 2001 From: Kelly Davis Date: Tue, 24 May 2016 16:18:57 +0200 Subject: [PATCH] Fixed Issue #47 (say command should use Voice with the default language) and Issue #53 (say command should use a 'concrete' AudioFormat) --- .../SayConsoleCommandExtension.java | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/bundles/io/org.eclipse.smarthome.io.voice/src/main/java/org/eclipse/smarthome/io/voice/internal/extensions/SayConsoleCommandExtension.java b/bundles/io/org.eclipse.smarthome.io.voice/src/main/java/org/eclipse/smarthome/io/voice/internal/extensions/SayConsoleCommandExtension.java index 69e08a59..8a2be3a8 100644 --- a/bundles/io/org.eclipse.smarthome.io.voice/src/main/java/org/eclipse/smarthome/io/voice/internal/extensions/SayConsoleCommandExtension.java +++ b/bundles/io/org.eclipse.smarthome.io.voice/src/main/java/org/eclipse/smarthome/io/voice/internal/extensions/SayConsoleCommandExtension.java @@ -7,9 +7,11 @@ */ package org.eclipse.smarthome.io.voice.internal.extensions; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Set; import org.eclipse.smarthome.core.items.Item; @@ -77,8 +79,12 @@ public class SayConsoleCommandExtension extends AbstractConsoleCommandExtension if (ttsService != null) { Set voices = ttsService.getAvailableVoices(); Set audioFormats = ttsService.getSupportedFormats(); + + Voice voice = getPreferedVoice(voices); + AudioFormat audioFormat = getPreferedAudioFormat(audioFormats); + try { - AudioSource audioSource = ttsService.synthesize(msg.toString(), voices.iterator().next(), audioFormats.iterator().next()); + AudioSource audioSource = ttsService.synthesize(msg.toString(), voice, audioFormat); AudioPlayer audioPlayer = new AudioPlayer(audioSource); audioPlayer.start(); audioPlayer.join(); @@ -93,6 +99,113 @@ public class SayConsoleCommandExtension extends AbstractConsoleCommandExtension } } + protected Voice getPreferedVoice(Set voices) { + // Express preferences with a Language Priority List + Locale locale = Locale.getDefault(); + String ranges = locale.toLanguageTag(); + List languageRanges = Locale.LanguageRange.parse(ranges); + + // Get collection of voice locales + Collection locales = new ArrayList(); + for (Voice currentVoice : voices) { + locales.add(currentVoice.getLocale()); + } + + // Determine prefered locale based on RFC 4647 + Locale preferedLocale = Locale.lookup(languageRanges,locales); + + // As a last resort choose some Locale + if (null == preferedLocale) { + preferedLocale = locales.iterator().next(); + } + + // Determine prefered voice + Voice preferedVoice = null; + for (Voice currentVoice : voices) { + if (preferedLocale.equals(currentVoice.getLocale())) { + preferedVoice = currentVoice; + } + } + assert (preferedVoice != null); + + // Return prefered voice + return preferedVoice; + } + + protected AudioFormat getPreferedAudioFormat(Set audioFormats) { + // Return the first concrete AudioFormat found + for (AudioFormat currentAudioFormat : audioFormats) { + // Check if currentAudioFormat is abstract + if (null == currentAudioFormat.getCodec()) { continue; } + if (null == currentAudioFormat.getContainer()) { continue; } + if (null == currentAudioFormat.isBigEndian()) { continue; } + if (null == currentAudioFormat.getBitDepth()) { continue; } + if (null == currentAudioFormat.getBitRate()) { continue; } + if (null == currentAudioFormat.getFrequency()) { continue; } + + // Prefer WAVE container + if (!currentAudioFormat.getContainer().equals("WAVE")) { continue; } + + // As currentAudioFormat is concreate, use it + return currentAudioFormat; + } + + // There's no concrete AudioFormat so we must create one + for (AudioFormat currentAudioFormat : audioFormats) { + // Define AudioFormat to return + AudioFormat format = currentAudioFormat; + + // Not all Codecs and containers can be supported + if (null == format.getCodec()) { continue; } + if (null == format.getContainer()) { continue; } + + // Prefer WAVE container + if (!format.getContainer().equals("WAVE")) { continue; } + + // If required set BigEndian, BitDepth, BitRate, and Frequency to default values + if (null == format.isBigEndian()) { + format = new AudioFormat(format.getContainer(), format.getCodec(), new Boolean(true), format.getBitDepth(), format.getBitRate(), format.getFrequency()); + } + if (null == format.getBitDepth() || null == format.getBitRate() || null == format.getFrequency()) { + // Define default values + int defaultBitDepth = 16; + int defaultBitRate = 262144; + long defaultFrequency = 16384; + + // Obtain current values + Integer bitRate = format.getBitRate(); + Long frequency = format.getFrequency(); + Integer bitDepth = format.getBitDepth(); + + // These values must be interdependent (bitRate = bitDepth * frequency) + if (null == bitRate) { + if (null == bitDepth) { bitDepth = new Integer(defaultBitDepth); } + if (null == frequency) { frequency = new Long(defaultFrequency); } + bitRate = new Integer(bitDepth.intValue() * frequency.intValue()); + } else if (null == bitDepth) { + if (null == frequency) { frequency = new Long(defaultFrequency); } + if (null == bitRate) { bitRate = new Integer(defaultBitRate); } + bitDepth = new Integer(bitRate.intValue() / frequency.intValue()); + } else if (null == frequency) { + if (null == bitRate) { bitRate = new Integer(defaultBitRate); } + if (null == bitDepth) { bitDepth = new Integer(defaultBitDepth); } + frequency = new Long(bitRate.longValue() / bitDepth.longValue()); + } + + format = new AudioFormat(format.getContainer(), format.getCodec(), format.isBigEndian(), bitDepth, bitRate, frequency); + } + + // Retrun prefered AudioFormat + return format; + } + + // Indicates the passed audioFormats is empty or specified no codecs or containers + assert (false); + + // Return null indicating failue + return null; + } + protected void setItemRegistry(ItemRegistry itemRegistry) { this.itemRegistry = itemRegistry; }