1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package android.speech.tts; 18 19 import android.annotation.Nullable; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 23 import java.util.ArrayList; 24 import java.util.Collections; 25 import java.util.HashSet; 26 import java.util.Locale; 27 import java.util.Set; 28 29 /** 30 * Characteristics and features of a Text-To-Speech Voice. Each TTS Engine can expose 31 * multiple voices for each locale, with different set of features. 32 */ 33 public class Voice implements Parcelable { 34 /** Very low, but still intelligible quality of speech synthesis */ 35 public static final int QUALITY_VERY_LOW = 100; 36 37 /** Low, not human-like quality of speech synthesis */ 38 public static final int QUALITY_LOW = 200; 39 40 /** Normal quality of speech synthesis */ 41 public static final int QUALITY_NORMAL = 300; 42 43 /** High, human-like quality of speech synthesis */ 44 public static final int QUALITY_HIGH = 400; 45 46 /** Very high, almost human-indistinguishable quality of speech synthesis */ 47 public static final int QUALITY_VERY_HIGH = 500; 48 49 /** Very low expected synthesizer latency (< 20ms) */ 50 public static final int LATENCY_VERY_LOW = 100; 51 52 /** Low expected synthesizer latency (~20ms) */ 53 public static final int LATENCY_LOW = 200; 54 55 /** Normal expected synthesizer latency (~50ms) */ 56 public static final int LATENCY_NORMAL = 300; 57 58 /** Network based expected synthesizer latency (~200ms) */ 59 public static final int LATENCY_HIGH = 400; 60 61 /** Very slow network based expected synthesizer latency (> 200ms) */ 62 public static final int LATENCY_VERY_HIGH = 500; 63 64 private final String mName; 65 private final Locale mLocale; 66 private final int mQuality; 67 private final int mLatency; 68 private final boolean mRequiresNetworkConnection; 69 private final Set<String> mFeatures; 70 Voice(String name, Locale locale, int quality, int latency, boolean requiresNetworkConnection, Set<String> features)71 public Voice(String name, 72 Locale locale, 73 int quality, 74 int latency, 75 boolean requiresNetworkConnection, 76 Set<String> features) { 77 this.mName = name; 78 this.mLocale = locale; 79 this.mQuality = quality; 80 this.mLatency = latency; 81 this.mRequiresNetworkConnection = requiresNetworkConnection; 82 this.mFeatures = features; 83 } 84 Voice(Parcel in)85 private Voice(Parcel in) { 86 this.mName = in.readString(); 87 this.mLocale = (Locale)in.readSerializable(java.util.Locale.class.getClassLoader(), java.util.Locale.class); 88 this.mQuality = in.readInt(); 89 this.mLatency = in.readInt(); 90 this.mRequiresNetworkConnection = (in.readByte() == 1); 91 this.mFeatures = new HashSet<String>(); 92 Collections.addAll(this.mFeatures, in.readStringArray()); 93 } 94 95 @Override writeToParcel(Parcel dest, int flags)96 public void writeToParcel(Parcel dest, int flags) { 97 dest.writeString(mName); 98 dest.writeSerializable(mLocale); 99 dest.writeInt(mQuality); 100 dest.writeInt(mLatency); 101 dest.writeByte((byte) (mRequiresNetworkConnection ? 1 : 0)); 102 dest.writeStringList(new ArrayList<String>(mFeatures)); 103 } 104 105 @Override describeContents()106 public int describeContents() { 107 return 0; 108 } 109 110 public static final @android.annotation.NonNull Parcelable.Creator<Voice> CREATOR = new Parcelable.Creator<Voice>() { 111 @Override 112 public Voice createFromParcel(Parcel in) { 113 return new Voice(in); 114 } 115 116 @Override 117 public Voice[] newArray(int size) { 118 return new Voice[size]; 119 } 120 }; 121 122 123 /** 124 * @return The voice's locale 125 */ getLocale()126 public Locale getLocale() { 127 return mLocale; 128 } 129 130 /** 131 * @return The voice's quality (higher is better) 132 * @see #QUALITY_VERY_HIGH 133 * @see #QUALITY_HIGH 134 * @see #QUALITY_NORMAL 135 * @see #QUALITY_LOW 136 * @see #QUALITY_VERY_LOW 137 */ getQuality()138 public int getQuality() { 139 return mQuality; 140 } 141 142 /** 143 * @return The voice's latency (lower is better) 144 * @see #LATENCY_VERY_LOW 145 * @see #LATENCY_LOW 146 * @see #LATENCY_NORMAL 147 * @see #LATENCY_HIGH 148 * @see #LATENCY_VERY_HIGH 149 */ getLatency()150 public int getLatency() { 151 return mLatency; 152 } 153 154 /** 155 * @return Does the Voice require a network connection to work. 156 */ isNetworkConnectionRequired()157 public boolean isNetworkConnectionRequired() { 158 return mRequiresNetworkConnection; 159 } 160 161 /** 162 * @return Unique voice name. 163 */ getName()164 public String getName() { 165 return mName; 166 } 167 168 /** 169 * Returns the set of features it supports for a given voice. 170 * Features can either be framework defined, e.g. 171 * {@link TextToSpeech.Engine#KEY_FEATURE_NETWORK_TIMEOUT_MS} or engine specific. 172 * Engine specific keys must be prefixed by the name of the engine they 173 * are intended for. These keys can be used as parameters to 174 * {@link TextToSpeech#speak(String, int, java.util.HashMap)} and 175 * {@link TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)}. 176 * 177 * Features values are strings and their values must met restrictions described in their 178 * documentation. 179 * 180 * @return Set instance. May return {@code null} on error. 181 */ getFeatures()182 public Set<String> getFeatures() { 183 return mFeatures; 184 } 185 186 @Override toString()187 public String toString() { 188 StringBuilder builder = new StringBuilder(64); 189 return builder.append("Voice[Name: ").append(mName) 190 .append(", locale: ").append(mLocale) 191 .append(", quality: ").append(mQuality) 192 .append(", latency: ").append(mLatency) 193 .append(", requiresNetwork: ").append(mRequiresNetworkConnection) 194 .append(", features: ").append(mFeatures.toString()) 195 .append("]").toString(); 196 } 197 198 @Override hashCode()199 public int hashCode() { 200 final int prime = 31; 201 int result = 1; 202 result = prime * result + ((mFeatures == null) ? 0 : mFeatures.hashCode()); 203 result = prime * result + mLatency; 204 result = prime * result + ((mLocale == null) ? 0 : mLocale.hashCode()); 205 result = prime * result + ((mName == null) ? 0 : mName.hashCode()); 206 result = prime * result + mQuality; 207 result = prime * result + (mRequiresNetworkConnection ? 1231 : 1237); 208 return result; 209 } 210 211 @Override equals(@ullable Object obj)212 public boolean equals(@Nullable Object obj) { 213 if (this == obj) { 214 return true; 215 } 216 if (obj == null) { 217 return false; 218 } 219 if (getClass() != obj.getClass()) { 220 return false; 221 } 222 Voice other = (Voice) obj; 223 if (mFeatures == null) { 224 if (other.mFeatures != null) { 225 return false; 226 } 227 } else if (!mFeatures.equals(other.mFeatures)) { 228 return false; 229 } 230 if (mLatency != other.mLatency) { 231 return false; 232 } 233 if (mLocale == null) { 234 if (other.mLocale != null) { 235 return false; 236 } 237 } else if (!mLocale.equals(other.mLocale)) { 238 return false; 239 } 240 if (mName == null) { 241 if (other.mName != null) { 242 return false; 243 } 244 } else if (!mName.equals(other.mName)) { 245 return false; 246 } 247 if (mQuality != other.mQuality) { 248 return false; 249 } 250 if (mRequiresNetworkConnection != other.mRequiresNetworkConnection) { 251 return false; 252 } 253 return true; 254 } 255 } 256