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