blob: b808088c4ee59b234cad1d288eacc0c3018eb763 [file] [log] [blame]
Sandeepd7018202014-07-10 15:15:39 -07001/**
Eric Laurente48188c2014-04-18 17:44:11 -07002 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.hardware.soundtrigger;
18
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080019import static android.system.OsConstants.EINVAL;
20import static android.system.OsConstants.ENODEV;
21import static android.system.OsConstants.ENOSYS;
22import static android.system.OsConstants.EPERM;
23import static android.system.OsConstants.EPIPE;
24
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080025import static java.util.Objects.requireNonNull;
26
Aurimas Liutikas4d1699d2019-08-28 13:01:05 -070027import android.annotation.NonNull;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080028import android.annotation.Nullable;
29import android.annotation.SystemApi;
jiabin1f4b4dd2019-03-18 18:07:03 -070030import android.app.ActivityThread;
Artur Satayev26958002019-12-10 17:47:52 +000031import android.compat.annotation.UnsupportedAppUsage;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080032import android.content.Context;
Eric Laurentd3b82232014-07-30 08:57:39 -070033import android.media.AudioFormat;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080034import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
35import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
Eric Laurente48188c2014-04-18 17:44:11 -070036import android.os.Handler;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080037import android.os.IBinder;
38import android.os.Looper;
Sandeep Siddhartha05589722014-07-17 16:21:54 -070039import android.os.Parcel;
40import android.os.Parcelable;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080041import android.os.RemoteException;
42import android.os.ServiceManager;
43import android.util.Log;
Eric Laurente48188c2014-04-18 17:44:11 -070044
45import java.util.ArrayList;
Sandeep Siddhartha05589722014-07-17 16:21:54 -070046import java.util.Arrays;
Eric Laurente48188c2014-04-18 17:44:11 -070047import java.util.UUID;
48
49/**
50 * The SoundTrigger class provides access via JNI to the native service managing
51 * the sound trigger HAL.
52 *
53 * @hide
54 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080055@SystemApi
Eric Laurente48188c2014-04-18 17:44:11 -070056public class SoundTrigger {
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080057 private static final String TAG = "SoundTrigger";
Eric Laurente48188c2014-04-18 17:44:11 -070058
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080059 private SoundTrigger() {
60 }
61
62 /**
63 * Status code used when the operation succeeded
64 */
Eric Laurente48188c2014-04-18 17:44:11 -070065 public static final int STATUS_OK = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080066 /** @hide */
Eric Laurente48188c2014-04-18 17:44:11 -070067 public static final int STATUS_ERROR = Integer.MIN_VALUE;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080068 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020069 public static final int STATUS_PERMISSION_DENIED = -EPERM;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080070 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020071 public static final int STATUS_NO_INIT = -ENODEV;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080072 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020073 public static final int STATUS_BAD_VALUE = -EINVAL;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080074 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020075 public static final int STATUS_DEAD_OBJECT = -EPIPE;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080076 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020077 public static final int STATUS_INVALID_OPERATION = -ENOSYS;
Eric Laurente48188c2014-04-18 17:44:11 -070078
79 /*****************************************************************************
80 * A ModuleProperties describes a given sound trigger hardware module
81 * managed by the native sound trigger service. Each module has a unique
82 * ID used to target any API call to this paricular module. Module
83 * properties are returned by listModules() method.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080084 *
Eric Laurente48188c2014-04-18 17:44:11 -070085 ****************************************************************************/
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070086 public static final class ModuleProperties implements Parcelable {
Eric Laurente48188c2014-04-18 17:44:11 -070087 /** Unique module ID provided by the native service */
88 public final int id;
89
90 /** human readable voice detection engine implementor */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070091 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -070092 public final String implementor;
93
94 /** human readable voice detection engine description */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070095 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -070096 public final String description;
97
98 /** Unique voice engine Id (changes with each version) */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070099 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700100 public final UUID uuid;
101
102 /** Voice detection engine version */
103 public final int version;
104
105 /** Maximum number of active sound models */
106 public final int maxSoundModels;
107
108 /** Maximum number of key phrases */
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700109 public final int maxKeyphrases;
Eric Laurente48188c2014-04-18 17:44:11 -0700110
111 /** Maximum number of users per key phrase */
112 public final int maxUsers;
113
114 /** Supported recognition modes (bit field, RECOGNITION_MODE_VOICE_TRIGGER ...) */
115 public final int recognitionModes;
116
117 /** Supports seamless transition to capture mode after recognition */
118 public final boolean supportsCaptureTransition;
119
120 /** Maximum buffering capacity in ms if supportsCaptureTransition() is true */
121 public final int maxBufferMs;
122
123 /** Supports capture by other use cases while detection is active */
124 public final boolean supportsConcurrentCapture;
125
126 /** Rated power consumption when detection is active with TDB silence/sound/speech ratio */
127 public final int powerConsumptionMw;
128
Eric Laurentd3b82232014-07-30 08:57:39 -0700129 /** Returns the trigger (key phrase) capture in the binary data of the
130 * recognition callback event */
131 public final boolean returnsTriggerInEvent;
132
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800133 ModuleProperties(int id, @NonNull String implementor, @NonNull String description,
134 @NonNull String uuid, int version, int maxSoundModels, int maxKeyphrases,
Eric Laurente48188c2014-04-18 17:44:11 -0700135 int maxUsers, int recognitionModes, boolean supportsCaptureTransition,
136 int maxBufferMs, boolean supportsConcurrentCapture,
Eric Laurentd3b82232014-07-30 08:57:39 -0700137 int powerConsumptionMw, boolean returnsTriggerInEvent) {
Eric Laurente48188c2014-04-18 17:44:11 -0700138 this.id = id;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800139 this.implementor = requireNonNull(implementor);
140 this.description = requireNonNull(description);
141 this.uuid = UUID.fromString(requireNonNull(uuid));
Eric Laurente48188c2014-04-18 17:44:11 -0700142 this.version = version;
143 this.maxSoundModels = maxSoundModels;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700144 this.maxKeyphrases = maxKeyphrases;
Eric Laurente48188c2014-04-18 17:44:11 -0700145 this.maxUsers = maxUsers;
146 this.recognitionModes = recognitionModes;
147 this.supportsCaptureTransition = supportsCaptureTransition;
148 this.maxBufferMs = maxBufferMs;
149 this.supportsConcurrentCapture = supportsConcurrentCapture;
150 this.powerConsumptionMw = powerConsumptionMw;
Eric Laurentd3b82232014-07-30 08:57:39 -0700151 this.returnsTriggerInEvent = returnsTriggerInEvent;
Eric Laurente48188c2014-04-18 17:44:11 -0700152 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700153
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700154 public static final @android.annotation.NonNull Parcelable.Creator<ModuleProperties> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700155 = new Parcelable.Creator<ModuleProperties>() {
156 public ModuleProperties createFromParcel(Parcel in) {
157 return ModuleProperties.fromParcel(in);
158 }
159
160 public ModuleProperties[] newArray(int size) {
161 return new ModuleProperties[size];
162 }
163 };
164
165 private static ModuleProperties fromParcel(Parcel in) {
166 int id = in.readInt();
167 String implementor = in.readString();
168 String description = in.readString();
169 String uuid = in.readString();
170 int version = in.readInt();
171 int maxSoundModels = in.readInt();
172 int maxKeyphrases = in.readInt();
173 int maxUsers = in.readInt();
174 int recognitionModes = in.readInt();
175 boolean supportsCaptureTransition = in.readByte() == 1;
176 int maxBufferMs = in.readInt();
177 boolean supportsConcurrentCapture = in.readByte() == 1;
178 int powerConsumptionMw = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -0700179 boolean returnsTriggerInEvent = in.readByte() == 1;
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700180 return new ModuleProperties(id, implementor, description, uuid, version,
181 maxSoundModels, maxKeyphrases, maxUsers, recognitionModes,
182 supportsCaptureTransition, maxBufferMs, supportsConcurrentCapture,
Eric Laurentd3b82232014-07-30 08:57:39 -0700183 powerConsumptionMw, returnsTriggerInEvent);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700184 }
185
186 @Override
187 public void writeToParcel(Parcel dest, int flags) {
188 dest.writeInt(id);
189 dest.writeString(implementor);
190 dest.writeString(description);
191 dest.writeString(uuid.toString());
192 dest.writeInt(version);
193 dest.writeInt(maxSoundModels);
194 dest.writeInt(maxKeyphrases);
195 dest.writeInt(maxUsers);
196 dest.writeInt(recognitionModes);
197 dest.writeByte((byte) (supportsCaptureTransition ? 1 : 0));
198 dest.writeInt(maxBufferMs);
199 dest.writeByte((byte) (supportsConcurrentCapture ? 1 : 0));
200 dest.writeInt(powerConsumptionMw);
Eric Laurentd3b82232014-07-30 08:57:39 -0700201 dest.writeByte((byte) (returnsTriggerInEvent ? 1 : 0));
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700202 }
203
204 @Override
205 public int describeContents() {
206 return 0;
207 }
208
209 @Override
210 public String toString() {
211 return "ModuleProperties [id=" + id + ", implementor=" + implementor + ", description="
212 + description + ", uuid=" + uuid + ", version=" + version + ", maxSoundModels="
213 + maxSoundModels + ", maxKeyphrases=" + maxKeyphrases + ", maxUsers="
214 + maxUsers + ", recognitionModes=" + recognitionModes
215 + ", supportsCaptureTransition=" + supportsCaptureTransition + ", maxBufferMs="
216 + maxBufferMs + ", supportsConcurrentCapture=" + supportsConcurrentCapture
Eric Laurentd3b82232014-07-30 08:57:39 -0700217 + ", powerConsumptionMw=" + powerConsumptionMw
218 + ", returnsTriggerInEvent=" + returnsTriggerInEvent + "]";
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700219 }
Eric Laurente48188c2014-04-18 17:44:11 -0700220 }
221
222 /*****************************************************************************
223 * A SoundModel describes the attributes and contains the binary data used by the hardware
224 * implementation to detect a particular sound pattern.
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700225 * A specialized version {@link KeyphraseSoundModel} is defined for key phrase
Eric Laurente48188c2014-04-18 17:44:11 -0700226 * sound models.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800227 *
228 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -0700229 ****************************************************************************/
230 public static class SoundModel {
231 /** Undefined sound model type */
232 public static final int TYPE_UNKNOWN = -1;
233
234 /** Keyphrase sound model */
235 public static final int TYPE_KEYPHRASE = 0;
236
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800237 /**
238 * A generic sound model. Use this type only for non-keyphrase sound models such as
239 * ones that match a particular sound pattern.
240 */
241 public static final int TYPE_GENERIC_SOUND = 1;
242
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700243 /** Unique sound model identifier */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100244 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800245 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700246 public final UUID uuid;
247
Eric Laurente48188c2014-04-18 17:44:11 -0700248 /** Sound model type (e.g. TYPE_KEYPHRASE); */
249 public final int type;
250
Eric Laurentd3b82232014-07-30 08:57:39 -0700251 /** Unique sound model vendor identifier */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100252 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800253 @NonNull
Eric Laurentd3b82232014-07-30 08:57:39 -0700254 public final UUID vendorUuid;
255
Eric Laurente48188c2014-04-18 17:44:11 -0700256 /** Opaque data. For use by vendor implementation and enrollment application */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100257 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800258 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700259 public final byte[] data;
260
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800261 public SoundModel(@NonNull UUID uuid, @Nullable UUID vendorUuid, int type,
262 @Nullable byte[] data) {
263 this.uuid = requireNonNull(uuid);
264 this.vendorUuid = vendorUuid != null ? vendorUuid : new UUID(0, 0);
Eric Laurente48188c2014-04-18 17:44:11 -0700265 this.type = type;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800266 this.data = data != null ? data : new byte[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700267 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700268
269 @Override
270 public int hashCode() {
271 final int prime = 31;
272 int result = 1;
273 result = prime * result + Arrays.hashCode(data);
274 result = prime * result + type;
275 result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
276 result = prime * result + ((vendorUuid == null) ? 0 : vendorUuid.hashCode());
277 return result;
278 }
279
280 @Override
281 public boolean equals(Object obj) {
282 if (this == obj)
283 return true;
284 if (obj == null)
285 return false;
286 if (!(obj instanceof SoundModel))
287 return false;
288 SoundModel other = (SoundModel) obj;
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700289 if (type != other.type)
290 return false;
291 if (uuid == null) {
292 if (other.uuid != null)
293 return false;
294 } else if (!uuid.equals(other.uuid))
295 return false;
296 if (vendorUuid == null) {
297 if (other.vendorUuid != null)
298 return false;
299 } else if (!vendorUuid.equals(other.vendorUuid))
300 return false;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800301 if (!Arrays.equals(data, other.data))
302 return false;
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700303 return true;
304 }
Eric Laurente48188c2014-04-18 17:44:11 -0700305 }
306
307 /*****************************************************************************
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700308 * A Keyphrase describes a key phrase that can be detected by a
309 * {@link KeyphraseSoundModel}
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800310 *
311 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -0700312 ****************************************************************************/
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700313 public static class Keyphrase implements Parcelable {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700314 /** Unique identifier for this keyphrase */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100315 @UnsupportedAppUsage
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700316 public final int id;
317
Eric Laurente48188c2014-04-18 17:44:11 -0700318 /** Recognition modes supported for this key phrase in the model */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100319 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700320 public final int recognitionModes;
321
322 /** Locale of the keyphrase. JAVA Locale string e.g en_US */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100323 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800324 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700325 public final String locale;
326
327 /** Key phrase text */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100328 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800329 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700330 public final String text;
331
Eric Laurent013f66b2014-07-06 16:35:00 -0700332 /** Users this key phrase has been trained for. countains sound trigger specific user IDs
333 * derived from system user IDs {@link android.os.UserHandle#getIdentifier()}. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100334 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800335 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -0700336 public final int[] users;
Eric Laurente48188c2014-04-18 17:44:11 -0700337
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100338 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800339 public Keyphrase(int id, int recognitionModes, @NonNull String locale, @NonNull String text,
340 @Nullable int[] users) {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700341 this.id = id;
Eric Laurente48188c2014-04-18 17:44:11 -0700342 this.recognitionModes = recognitionModes;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800343 this.locale = requireNonNull(locale);
344 this.text = requireNonNull(text);
345 this.users = users != null ? users : new int[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700346 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700347
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700348 public static final @android.annotation.NonNull Parcelable.Creator<Keyphrase> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700349 = new Parcelable.Creator<Keyphrase>() {
350 public Keyphrase createFromParcel(Parcel in) {
351 return Keyphrase.fromParcel(in);
352 }
353
354 public Keyphrase[] newArray(int size) {
355 return new Keyphrase[size];
356 }
357 };
358
359 private static Keyphrase fromParcel(Parcel in) {
360 int id = in.readInt();
361 int recognitionModes = in.readInt();
362 String locale = in.readString();
363 String text = in.readString();
364 int[] users = null;
365 int numUsers = in.readInt();
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700366 if (numUsers >= 0) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700367 users = new int[numUsers];
368 in.readIntArray(users);
369 }
370 return new Keyphrase(id, recognitionModes, locale, text, users);
371 }
372
373 @Override
374 public void writeToParcel(Parcel dest, int flags) {
375 dest.writeInt(id);
376 dest.writeInt(recognitionModes);
377 dest.writeString(locale);
378 dest.writeString(text);
379 if (users != null) {
380 dest.writeInt(users.length);
381 dest.writeIntArray(users);
382 } else {
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700383 dest.writeInt(-1);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700384 }
385 }
386
387 @Override
388 public int describeContents() {
389 return 0;
390 }
391
392 @Override
393 public int hashCode() {
394 final int prime = 31;
395 int result = 1;
396 result = prime * result + ((text == null) ? 0 : text.hashCode());
397 result = prime * result + id;
398 result = prime * result + ((locale == null) ? 0 : locale.hashCode());
399 result = prime * result + recognitionModes;
400 result = prime * result + Arrays.hashCode(users);
401 return result;
402 }
403
404 @Override
405 public boolean equals(Object obj) {
406 if (this == obj)
407 return true;
408 if (obj == null)
409 return false;
410 if (getClass() != obj.getClass())
411 return false;
412 Keyphrase other = (Keyphrase) obj;
413 if (text == null) {
414 if (other.text != null)
415 return false;
416 } else if (!text.equals(other.text))
417 return false;
418 if (id != other.id)
419 return false;
420 if (locale == null) {
421 if (other.locale != null)
422 return false;
423 } else if (!locale.equals(other.locale))
424 return false;
425 if (recognitionModes != other.recognitionModes)
426 return false;
427 if (!Arrays.equals(users, other.users))
428 return false;
429 return true;
430 }
431
432 @Override
433 public String toString() {
434 return "Keyphrase [id=" + id + ", recognitionModes=" + recognitionModes + ", locale="
435 + locale + ", text=" + text + ", users=" + Arrays.toString(users) + "]";
436 }
Eric Laurente48188c2014-04-18 17:44:11 -0700437 }
438
439 /*****************************************************************************
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700440 * A KeyphraseSoundModel is a specialized {@link SoundModel} for key phrases.
Eric Laurente48188c2014-04-18 17:44:11 -0700441 * It contains data needed by the hardware to detect a certain number of key phrases
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700442 * and the list of corresponding {@link Keyphrase} descriptors.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800443 *
444 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -0700445 ****************************************************************************/
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700446 public static class KeyphraseSoundModel extends SoundModel implements Parcelable {
Eric Laurente48188c2014-04-18 17:44:11 -0700447 /** Key phrases in this sound model */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100448 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800449 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700450 public final Keyphrase[] keyphrases; // keyword phrases in model
Eric Laurente48188c2014-04-18 17:44:11 -0700451
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100452 @UnsupportedAppUsage
Eric Laurentd3b82232014-07-30 08:57:39 -0700453 public KeyphraseSoundModel(
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800454 @NonNull UUID uuid, @NonNull UUID vendorUuid, @Nullable byte[] data,
455 @Nullable Keyphrase[] keyphrases) {
Eric Laurentd3b82232014-07-30 08:57:39 -0700456 super(uuid, vendorUuid, TYPE_KEYPHRASE, data);
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800457 this.keyphrases = keyphrases != null ? keyphrases : new Keyphrase[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700458 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700459
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700460 public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseSoundModel> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700461 = new Parcelable.Creator<KeyphraseSoundModel>() {
462 public KeyphraseSoundModel createFromParcel(Parcel in) {
463 return KeyphraseSoundModel.fromParcel(in);
464 }
465
466 public KeyphraseSoundModel[] newArray(int size) {
467 return new KeyphraseSoundModel[size];
468 }
469 };
470
471 private static KeyphraseSoundModel fromParcel(Parcel in) {
472 UUID uuid = UUID.fromString(in.readString());
Eric Laurentd3b82232014-07-30 08:57:39 -0700473 UUID vendorUuid = null;
474 int length = in.readInt();
475 if (length >= 0) {
476 vendorUuid = UUID.fromString(in.readString());
477 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700478 byte[] data = in.readBlob();
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700479 Keyphrase[] keyphrases = in.createTypedArray(Keyphrase.CREATOR);
Eric Laurentd3b82232014-07-30 08:57:39 -0700480 return new KeyphraseSoundModel(uuid, vendorUuid, data, keyphrases);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700481 }
482
483 @Override
484 public int describeContents() {
485 return 0;
486 }
487
488 @Override
489 public void writeToParcel(Parcel dest, int flags) {
490 dest.writeString(uuid.toString());
Eric Laurentd3b82232014-07-30 08:57:39 -0700491 if (vendorUuid == null) {
492 dest.writeInt(-1);
493 } else {
494 dest.writeInt(vendorUuid.toString().length());
495 dest.writeString(vendorUuid.toString());
496 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700497 dest.writeBlob(data);
Sandeep Siddhartha68173372014-07-28 13:25:30 -0700498 dest.writeTypedArray(keyphrases, flags);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700499 }
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700500
501 @Override
502 public String toString() {
Eric Laurentd3b82232014-07-30 08:57:39 -0700503 return "KeyphraseSoundModel [keyphrases=" + Arrays.toString(keyphrases)
504 + ", uuid=" + uuid + ", vendorUuid=" + vendorUuid
505 + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]";
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700506 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700507
508 @Override
509 public int hashCode() {
510 final int prime = 31;
511 int result = super.hashCode();
512 result = prime * result + Arrays.hashCode(keyphrases);
513 return result;
514 }
515
516 @Override
517 public boolean equals(Object obj) {
518 if (this == obj)
519 return true;
520 if (!super.equals(obj))
521 return false;
522 if (!(obj instanceof KeyphraseSoundModel))
523 return false;
524 KeyphraseSoundModel other = (KeyphraseSoundModel) obj;
525 if (!Arrays.equals(keyphrases, other.keyphrases))
526 return false;
527 return true;
528 }
Eric Laurente48188c2014-04-18 17:44:11 -0700529 }
530
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800531
532 /*****************************************************************************
533 * A GenericSoundModel is a specialized {@link SoundModel} for non-voice sound
534 * patterns.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800535 *
536 * @hide
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800537 ****************************************************************************/
538 public static class GenericSoundModel extends SoundModel implements Parcelable {
539
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700540 public static final @android.annotation.NonNull Parcelable.Creator<GenericSoundModel> CREATOR
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800541 = new Parcelable.Creator<GenericSoundModel>() {
542 public GenericSoundModel createFromParcel(Parcel in) {
543 return GenericSoundModel.fromParcel(in);
544 }
545
546 public GenericSoundModel[] newArray(int size) {
547 return new GenericSoundModel[size];
548 }
549 };
550
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100551 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800552 public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
553 @Nullable byte[] data) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800554 super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data);
555 }
556
557 @Override
558 public int describeContents() {
559 return 0;
560 }
561
562 private static GenericSoundModel fromParcel(Parcel in) {
563 UUID uuid = UUID.fromString(in.readString());
564 UUID vendorUuid = null;
565 int length = in.readInt();
566 if (length >= 0) {
567 vendorUuid = UUID.fromString(in.readString());
568 }
569 byte[] data = in.readBlob();
570 return new GenericSoundModel(uuid, vendorUuid, data);
571 }
572
573 @Override
574 public void writeToParcel(Parcel dest, int flags) {
575 dest.writeString(uuid.toString());
576 if (vendorUuid == null) {
577 dest.writeInt(-1);
578 } else {
579 dest.writeInt(vendorUuid.toString().length());
580 dest.writeString(vendorUuid.toString());
581 }
582 dest.writeBlob(data);
583 }
584
585 @Override
586 public String toString() {
587 return "GenericSoundModel [uuid=" + uuid + ", vendorUuid=" + vendorUuid
588 + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]";
589 }
590 }
591
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700592 /*****************************************************************************
593 * A ModelParamRange is a representation of supported parameter range for a
594 * given loaded model.
595 ****************************************************************************/
596 public static final class ModelParamRange implements Parcelable {
597
598 /**
599 * start of supported range inclusive
600 */
601 public final int start;
602
603 /**
604 * end of supported range inclusive
605 */
606 public final int end;
607
608 ModelParamRange(int start, int end) {
609 this.start = start;
610 this.end = end;
611 }
612
613 private ModelParamRange(@NonNull Parcel in) {
614 this.start = in.readInt();
615 this.end = in.readInt();
616 }
617
618 @NonNull
619 public static final Creator<ModelParamRange> CREATOR = new Creator<ModelParamRange>() {
620 @Override
621 @NonNull
622 public ModelParamRange createFromParcel(@NonNull Parcel in) {
623 return new ModelParamRange(in);
624 }
625
626 @Override
627 @NonNull
628 public ModelParamRange[] newArray(int size) {
629 return new ModelParamRange[size];
630 }
631 };
632
633 @Override
634 public int describeContents() {
635 return 0;
636 }
637
638 @Override
639 public void writeToParcel(@NonNull Parcel dest, int flags) {
640 dest.writeInt(start);
641 dest.writeInt(end);
642 }
643
644 @Override
645 @NonNull
646 public String toString() {
647 return "ModelParamRange [start=" + start + ", end=" + end + "]";
648 }
649 }
650
Eric Laurente48188c2014-04-18 17:44:11 -0700651 /**
652 * Modes for key phrase recognition
653 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800654
655 /**
656 * Simple recognition of the key phrase
657 *
658 * @hide
659 */
Eric Laurente48188c2014-04-18 17:44:11 -0700660 public static final int RECOGNITION_MODE_VOICE_TRIGGER = 0x1;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800661 /**
662 * Trigger only if one user is identified
663 *
664 * @hide
665 */
Eric Laurente48188c2014-04-18 17:44:11 -0700666 public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 0x2;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800667 /**
668 * Trigger only if one user is authenticated
669 *
670 * @hide
671 */
Eric Laurente48188c2014-04-18 17:44:11 -0700672 public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 0x4;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800673 /**
674 * Generic (non-speech) recognition.
675 *
676 * @hide
677 */
678 public static final int RECOGNITION_MODE_GENERIC = 0x8;
Eric Laurente48188c2014-04-18 17:44:11 -0700679
680 /**
681 * Status codes for {@link RecognitionEvent}
682 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800683 /**
684 * Recognition success
685 *
686 * @hide
687 */
Eric Laurente48188c2014-04-18 17:44:11 -0700688 public static final int RECOGNITION_STATUS_SUCCESS = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800689 /**
690 * Recognition aborted (e.g. capture preempted by anotehr use case
691 *
692 * @hide
693 */
Eric Laurente48188c2014-04-18 17:44:11 -0700694 public static final int RECOGNITION_STATUS_ABORT = 1;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800695 /**
696 * Recognition failure
697 *
698 * @hide
699 */
Eric Laurente48188c2014-04-18 17:44:11 -0700700 public static final int RECOGNITION_STATUS_FAILURE = 2;
mike dooleyb2ab04a2018-11-07 15:48:54 +0100701 /**
702 * Recognition event was triggered by a getModelState request, not by the
703 * DSP.
704 *
705 * @hide
706 */
707 public static final int RECOGNITION_STATUS_GET_STATE_RESPONSE = 3;
Eric Laurente48188c2014-04-18 17:44:11 -0700708
709 /**
710 * A RecognitionEvent is provided by the
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800711 * {@code StatusListener#onRecognition(RecognitionEvent)}
Eric Laurente48188c2014-04-18 17:44:11 -0700712 * callback upon recognition success or failure.
713 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800714 public static class RecognitionEvent {
715 /**
716 * Recognition status e.g RECOGNITION_STATUS_SUCCESS
717 *
718 * @hide
719 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100720 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700721 public final int status;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800722 /**
723 *
724 * Sound Model corresponding to this event callback
725 *
726 * @hide
727 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100728 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700729 public final int soundModelHandle;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800730 /**
731 * True if it is possible to capture audio from this utterance buffered by the hardware
732 *
733 * @hide
734 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100735 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700736 public final boolean captureAvailable;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800737 /**
738 * Audio session ID to be used when capturing the utterance with an AudioRecord
739 * if captureAvailable() is true.
740 *
741 * @hide
742 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100743 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700744 public final int captureSession;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800745 /**
746 * Delay in ms between end of model detection and start of audio available for capture.
747 * A negative value is possible (e.g. if keyphrase is also available for capture)
748 *
749 * @hide
750 */
Eric Laurente48188c2014-04-18 17:44:11 -0700751 public final int captureDelayMs;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800752 /**
753 * Duration in ms of audio captured before the start of the trigger. 0 if none.
754 *
755 * @hide
756 */
Eric Laurent013f66b2014-07-06 16:35:00 -0700757 public final int capturePreambleMs;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800758 /**
759 * True if the trigger (key phrase capture is present in binary data
760 *
761 * @hide
762 */
Eric Laurentd3b82232014-07-30 08:57:39 -0700763 public final boolean triggerInData;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800764 /**
765 * Audio format of either the trigger in event data or to use for capture of the
766 * rest of the utterance
767 *
768 * @hide
769 */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800770 @NonNull
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800771 public final AudioFormat captureFormat;
772 /**
773 * Opaque data for use by system applications who know about voice engine internals,
774 * typically during enrollment.
775 *
776 * @hide
777 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100778 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800779 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700780 public final byte[] data;
781
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800782 /** @hide */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100783 @UnsupportedAppUsage
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700784 public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -0700785 int captureSession, int captureDelayMs, int capturePreambleMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800786 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) {
Eric Laurente48188c2014-04-18 17:44:11 -0700787 this.status = status;
788 this.soundModelHandle = soundModelHandle;
789 this.captureAvailable = captureAvailable;
790 this.captureSession = captureSession;
791 this.captureDelayMs = captureDelayMs;
Eric Laurent013f66b2014-07-06 16:35:00 -0700792 this.capturePreambleMs = capturePreambleMs;
Eric Laurentd3b82232014-07-30 08:57:39 -0700793 this.triggerInData = triggerInData;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800794 this.captureFormat = requireNonNull(captureFormat);
795 this.data = data != null ? data : new byte[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700796 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700797
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800798 /**
799 * Check if is possible to capture audio from this utterance buffered by the hardware.
800 *
801 * @return {@code true} iff a capturing is possible
802 */
803 public boolean isCaptureAvailable() {
804 return captureAvailable;
805 }
806
807 /**
808 * Get the audio format of either the trigger in event data or to use for capture of the
809 * rest of the utterance
810 *
811 * @return the audio format
812 */
813 @Nullable public AudioFormat getCaptureFormat() {
814 return captureFormat;
815 }
816
817 /**
818 * Get Audio session ID to be used when capturing the utterance with an {@link AudioRecord}
819 * if {@link #isCaptureAvailable()} is true.
820 *
821 * @return The id of the capture session
822 */
823 public int getCaptureSession() {
824 return captureSession;
825 }
826
827 /**
828 * Get the opaque data for use by system applications who know about voice engine
829 * internals, typically during enrollment.
830 *
831 * @return The data of the event
832 */
833 public byte[] getData() {
834 return data;
835 }
836
837 /** @hide */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700838 public static final @android.annotation.NonNull Parcelable.Creator<RecognitionEvent> CREATOR
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700839 = new Parcelable.Creator<RecognitionEvent>() {
840 public RecognitionEvent createFromParcel(Parcel in) {
841 return RecognitionEvent.fromParcel(in);
842 }
843
844 public RecognitionEvent[] newArray(int size) {
845 return new RecognitionEvent[size];
846 }
847 };
848
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800849 /** @hide */
Arunesh Mishraf47f1732016-02-18 16:16:12 -0800850 protected static RecognitionEvent fromParcel(Parcel in) {
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700851 int status = in.readInt();
852 int soundModelHandle = in.readInt();
853 boolean captureAvailable = in.readByte() == 1;
854 int captureSession = in.readInt();
855 int captureDelayMs = in.readInt();
856 int capturePreambleMs = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -0700857 boolean triggerInData = in.readByte() == 1;
858 AudioFormat captureFormat = null;
Eric Laurent39fcca02014-09-05 16:44:19 -0700859 if (in.readByte() == 1) {
Eric Laurentd3b82232014-07-30 08:57:39 -0700860 int sampleRate = in.readInt();
861 int encoding = in.readInt();
862 int channelMask = in.readInt();
863 captureFormat = (new AudioFormat.Builder())
864 .setChannelMask(channelMask)
865 .setEncoding(encoding)
866 .setSampleRate(sampleRate)
867 .build();
868 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700869 byte[] data = in.readBlob();
870 return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession,
Eric Laurentd3b82232014-07-30 08:57:39 -0700871 captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700872 }
873
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800874 /** @hide */
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700875 public int describeContents() {
876 return 0;
877 }
878
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800879 /** @hide */
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700880 public void writeToParcel(Parcel dest, int flags) {
881 dest.writeInt(status);
882 dest.writeInt(soundModelHandle);
883 dest.writeByte((byte) (captureAvailable ? 1 : 0));
884 dest.writeInt(captureSession);
885 dest.writeInt(captureDelayMs);
886 dest.writeInt(capturePreambleMs);
Eric Laurent39fcca02014-09-05 16:44:19 -0700887 dest.writeByte((byte) (triggerInData ? 1 : 0));
888 if (captureFormat != null) {
Eric Laurentd3b82232014-07-30 08:57:39 -0700889 dest.writeByte((byte)1);
890 dest.writeInt(captureFormat.getSampleRate());
891 dest.writeInt(captureFormat.getEncoding());
892 dest.writeInt(captureFormat.getChannelMask());
893 } else {
894 dest.writeByte((byte)0);
895 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700896 dest.writeBlob(data);
897 }
898
899 @Override
900 public int hashCode() {
901 final int prime = 31;
902 int result = 1;
903 result = prime * result + (captureAvailable ? 1231 : 1237);
904 result = prime * result + captureDelayMs;
905 result = prime * result + capturePreambleMs;
906 result = prime * result + captureSession;
Eric Laurentd3b82232014-07-30 08:57:39 -0700907 result = prime * result + (triggerInData ? 1231 : 1237);
908 if (captureFormat != null) {
909 result = prime * result + captureFormat.getSampleRate();
910 result = prime * result + captureFormat.getEncoding();
911 result = prime * result + captureFormat.getChannelMask();
912 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700913 result = prime * result + Arrays.hashCode(data);
914 result = prime * result + soundModelHandle;
915 result = prime * result + status;
916 return result;
917 }
918
919 @Override
Aurimas Liutikas4d1699d2019-08-28 13:01:05 -0700920 public boolean equals(@Nullable Object obj) {
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700921 if (this == obj)
922 return true;
923 if (obj == null)
924 return false;
925 if (getClass() != obj.getClass())
926 return false;
927 RecognitionEvent other = (RecognitionEvent) obj;
928 if (captureAvailable != other.captureAvailable)
929 return false;
930 if (captureDelayMs != other.captureDelayMs)
931 return false;
932 if (capturePreambleMs != other.capturePreambleMs)
933 return false;
934 if (captureSession != other.captureSession)
935 return false;
936 if (!Arrays.equals(data, other.data))
937 return false;
938 if (soundModelHandle != other.soundModelHandle)
939 return false;
940 if (status != other.status)
941 return false;
Eric Laurentd3b82232014-07-30 08:57:39 -0700942 if (triggerInData != other.triggerInData)
943 return false;
Ryan Bavettaea04e8f2016-03-02 18:34:50 -0800944 if (captureFormat == null) {
945 if (other.captureFormat != null)
946 return false;
947 } else {
948 if (other.captureFormat == null)
949 return false;
950 if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
951 return false;
952 if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
953 return false;
954 if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
955 return false;
956 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700957 return true;
958 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -0700959
Aurimas Liutikas4d1699d2019-08-28 13:01:05 -0700960 @NonNull
Sandeep Siddhartha68173372014-07-28 13:25:30 -0700961 @Override
962 public String toString() {
963 return "RecognitionEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
964 + ", captureAvailable=" + captureAvailable + ", captureSession="
965 + captureSession + ", captureDelayMs=" + captureDelayMs
966 + ", capturePreambleMs=" + capturePreambleMs
Eric Laurentd3b82232014-07-30 08:57:39 -0700967 + ", triggerInData=" + triggerInData
968 + ((captureFormat == null) ? "" :
969 (", sampleRate=" + captureFormat.getSampleRate()))
970 + ((captureFormat == null) ? "" :
971 (", encoding=" + captureFormat.getEncoding()))
972 + ((captureFormat == null) ? "" :
973 (", channelMask=" + captureFormat.getChannelMask()))
Sandeep Siddhartha68173372014-07-28 13:25:30 -0700974 + ", data=" + (data == null ? 0 : data.length) + "]";
975 }
Eric Laurente48188c2014-04-18 17:44:11 -0700976 }
977
978 /**
Eric Laurent013f66b2014-07-06 16:35:00 -0700979 * A RecognitionConfig is provided to
980 * {@link SoundTriggerModule#startRecognition(int, RecognitionConfig)} to configure the
981 * recognition request.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800982 *
983 * @hide
Eric Laurent013f66b2014-07-06 16:35:00 -0700984 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700985 public static class RecognitionConfig implements Parcelable {
Eric Laurent013f66b2014-07-06 16:35:00 -0700986 /** True if the DSP should capture the trigger sound and make it available for further
987 * capture. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100988 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -0700989 public final boolean captureRequested;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -0700990 /**
991 * True if the service should restart listening after the DSP triggers.
992 * Note: This config flag is currently used at the service layer rather than by the DSP.
993 */
994 public final boolean allowMultipleTriggers;
Eric Laurent013f66b2014-07-06 16:35:00 -0700995 /** List of all keyphrases in the sound model for which recognition should be performed with
996 * options for each keyphrase. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100997 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800998 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -0700999 public final KeyphraseRecognitionExtra keyphrases[];
1000 /** Opaque data for use by system applications who know about voice engine internals,
1001 * typically during enrollment. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001002 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001003 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -07001004 public final byte[] data;
1005
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001006 @UnsupportedAppUsage
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001007 public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001008 @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001009 this.captureRequested = captureRequested;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001010 this.allowMultipleTriggers = allowMultipleTriggers;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001011 this.keyphrases = keyphrases != null ? keyphrases : new KeyphraseRecognitionExtra[0];
1012 this.data = data != null ? data : new byte[0];
Eric Laurent013f66b2014-07-06 16:35:00 -07001013 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001014
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001015 public static final @android.annotation.NonNull Parcelable.Creator<RecognitionConfig> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001016 = new Parcelable.Creator<RecognitionConfig>() {
1017 public RecognitionConfig createFromParcel(Parcel in) {
1018 return RecognitionConfig.fromParcel(in);
1019 }
1020
1021 public RecognitionConfig[] newArray(int size) {
1022 return new RecognitionConfig[size];
1023 }
1024 };
1025
1026 private static RecognitionConfig fromParcel(Parcel in) {
1027 boolean captureRequested = in.readByte() == 1;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001028 boolean allowMultipleTriggers = in.readByte() == 1;
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001029 KeyphraseRecognitionExtra[] keyphrases =
1030 in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001031 byte[] data = in.readBlob();
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001032 return new RecognitionConfig(captureRequested, allowMultipleTriggers, keyphrases, data);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001033 }
1034
1035 @Override
1036 public void writeToParcel(Parcel dest, int flags) {
1037 dest.writeByte((byte) (captureRequested ? 1 : 0));
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001038 dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0));
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001039 dest.writeTypedArray(keyphrases, flags);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001040 dest.writeBlob(data);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001041 }
1042
1043 @Override
1044 public int describeContents() {
1045 return 0;
1046 }
Sandeep Siddhartha110f5692014-07-20 12:22:56 -07001047
1048 @Override
1049 public String toString() {
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001050 return "RecognitionConfig [captureRequested=" + captureRequested
1051 + ", allowMultipleTriggers=" + allowMultipleTriggers + ", keyphrases="
1052 + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data) + "]";
Sandeep Siddhartha110f5692014-07-20 12:22:56 -07001053 }
Eric Laurent013f66b2014-07-06 16:35:00 -07001054 }
1055
1056 /**
1057 * Confidence level for users defined in a keyphrase.
1058 * - The confidence level is expressed in percent (0% -100%).
1059 * When used in a {@link KeyphraseRecognitionEvent} it indicates the detected confidence level
1060 * When used in a {@link RecognitionConfig} it indicates the minimum confidence level that
1061 * should trigger a recognition.
1062 * - The user ID is derived from the system ID {@link android.os.UserHandle#getIdentifier()}.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001063 *
1064 * @hide
Eric Laurent013f66b2014-07-06 16:35:00 -07001065 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001066 public static class ConfidenceLevel implements Parcelable {
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001067 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001068 public final int userId;
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001069 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001070 public final int confidenceLevel;
1071
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001072 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001073 public ConfidenceLevel(int userId, int confidenceLevel) {
1074 this.userId = userId;
1075 this.confidenceLevel = confidenceLevel;
1076 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001077
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001078 public static final @android.annotation.NonNull Parcelable.Creator<ConfidenceLevel> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001079 = new Parcelable.Creator<ConfidenceLevel>() {
1080 public ConfidenceLevel createFromParcel(Parcel in) {
1081 return ConfidenceLevel.fromParcel(in);
1082 }
1083
1084 public ConfidenceLevel[] newArray(int size) {
1085 return new ConfidenceLevel[size];
1086 }
1087 };
1088
1089 private static ConfidenceLevel fromParcel(Parcel in) {
1090 int userId = in.readInt();
1091 int confidenceLevel = in.readInt();
1092 return new ConfidenceLevel(userId, confidenceLevel);
1093 }
1094
1095 @Override
1096 public void writeToParcel(Parcel dest, int flags) {
1097 dest.writeInt(userId);
1098 dest.writeInt(confidenceLevel);
1099 }
1100
1101 @Override
1102 public int describeContents() {
1103 return 0;
1104 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001105
1106 @Override
1107 public int hashCode() {
1108 final int prime = 31;
1109 int result = 1;
1110 result = prime * result + confidenceLevel;
1111 result = prime * result + userId;
1112 return result;
1113 }
1114
1115 @Override
1116 public boolean equals(Object obj) {
1117 if (this == obj)
1118 return true;
1119 if (obj == null)
1120 return false;
1121 if (getClass() != obj.getClass())
1122 return false;
1123 ConfidenceLevel other = (ConfidenceLevel) obj;
1124 if (confidenceLevel != other.confidenceLevel)
1125 return false;
1126 if (userId != other.userId)
1127 return false;
1128 return true;
1129 }
1130
1131 @Override
1132 public String toString() {
1133 return "ConfidenceLevel [userId=" + userId
1134 + ", confidenceLevel=" + confidenceLevel + "]";
1135 }
Eric Laurent013f66b2014-07-06 16:35:00 -07001136 }
1137
1138 /**
Sandeep Siddharthad4233c62014-06-12 18:31:19 -07001139 * Additional data conveyed by a {@link KeyphraseRecognitionEvent}
Eric Laurente48188c2014-04-18 17:44:11 -07001140 * for a key phrase detection.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001141 *
1142 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001143 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001144 public static class KeyphraseRecognitionExtra implements Parcelable {
1145 /** The keyphrase ID */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001146 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001147 public final int id;
Eric Laurente48188c2014-04-18 17:44:11 -07001148
1149 /** Recognition modes matched for this event */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001150 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -07001151 public final int recognitionModes;
1152
Eric Laurentd3b82232014-07-30 08:57:39 -07001153 /** Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
1154 * is not performed */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001155 @UnsupportedAppUsage
Eric Laurentd3b82232014-07-30 08:57:39 -07001156 public final int coarseConfidenceLevel;
1157
Eric Laurent013f66b2014-07-06 16:35:00 -07001158 /** Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to
1159 * be recognized (RecognitionConfig) */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001160 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001161 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -07001162 public final ConfidenceLevel[] confidenceLevels;
1163
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001164 @UnsupportedAppUsage
Eric Laurentd3b82232014-07-30 08:57:39 -07001165 public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001166 @Nullable ConfidenceLevel[] confidenceLevels) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001167 this.id = id;
Eric Laurente48188c2014-04-18 17:44:11 -07001168 this.recognitionModes = recognitionModes;
Eric Laurentd3b82232014-07-30 08:57:39 -07001169 this.coarseConfidenceLevel = coarseConfidenceLevel;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001170 this.confidenceLevels =
1171 confidenceLevels != null ? confidenceLevels : new ConfidenceLevel[0];
Eric Laurente48188c2014-04-18 17:44:11 -07001172 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001173
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001174 public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionExtra> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001175 = new Parcelable.Creator<KeyphraseRecognitionExtra>() {
1176 public KeyphraseRecognitionExtra createFromParcel(Parcel in) {
1177 return KeyphraseRecognitionExtra.fromParcel(in);
1178 }
1179
1180 public KeyphraseRecognitionExtra[] newArray(int size) {
1181 return new KeyphraseRecognitionExtra[size];
1182 }
1183 };
1184
1185 private static KeyphraseRecognitionExtra fromParcel(Parcel in) {
1186 int id = in.readInt();
1187 int recognitionModes = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -07001188 int coarseConfidenceLevel = in.readInt();
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001189 ConfidenceLevel[] confidenceLevels = in.createTypedArray(ConfidenceLevel.CREATOR);
Eric Laurentd3b82232014-07-30 08:57:39 -07001190 return new KeyphraseRecognitionExtra(id, recognitionModes, coarseConfidenceLevel,
1191 confidenceLevels);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001192 }
1193
1194 @Override
1195 public void writeToParcel(Parcel dest, int flags) {
1196 dest.writeInt(id);
1197 dest.writeInt(recognitionModes);
Eric Laurentd3b82232014-07-30 08:57:39 -07001198 dest.writeInt(coarseConfidenceLevel);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001199 dest.writeTypedArray(confidenceLevels, flags);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001200 }
1201
1202 @Override
1203 public int describeContents() {
1204 return 0;
1205 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001206
1207 @Override
1208 public int hashCode() {
1209 final int prime = 31;
1210 int result = 1;
1211 result = prime * result + Arrays.hashCode(confidenceLevels);
1212 result = prime * result + id;
1213 result = prime * result + recognitionModes;
Eric Laurentd3b82232014-07-30 08:57:39 -07001214 result = prime * result + coarseConfidenceLevel;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001215 return result;
1216 }
1217
1218 @Override
1219 public boolean equals(Object obj) {
1220 if (this == obj)
1221 return true;
1222 if (obj == null)
1223 return false;
1224 if (getClass() != obj.getClass())
1225 return false;
1226 KeyphraseRecognitionExtra other = (KeyphraseRecognitionExtra) obj;
1227 if (!Arrays.equals(confidenceLevels, other.confidenceLevels))
1228 return false;
1229 if (id != other.id)
1230 return false;
1231 if (recognitionModes != other.recognitionModes)
1232 return false;
Eric Laurentd3b82232014-07-30 08:57:39 -07001233 if (coarseConfidenceLevel != other.coarseConfidenceLevel)
1234 return false;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001235 return true;
1236 }
1237
1238 @Override
1239 public String toString() {
1240 return "KeyphraseRecognitionExtra [id=" + id + ", recognitionModes=" + recognitionModes
Eric Laurentd3b82232014-07-30 08:57:39 -07001241 + ", coarseConfidenceLevel=" + coarseConfidenceLevel
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001242 + ", confidenceLevels=" + Arrays.toString(confidenceLevels) + "]";
1243 }
Eric Laurente48188c2014-04-18 17:44:11 -07001244 }
1245
1246 /**
1247 * Specialized {@link RecognitionEvent} for a key phrase detection.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001248 *
1249 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001250 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001251 public static class KeyphraseRecognitionEvent extends RecognitionEvent implements Parcelable {
Eric Laurente48188c2014-04-18 17:44:11 -07001252 /** Indicates if the key phrase is present in the buffered audio available for capture */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001253 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001254 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -07001255 public final KeyphraseRecognitionExtra[] keyphraseExtras;
Eric Laurente48188c2014-04-18 17:44:11 -07001256
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001257 @UnsupportedAppUsage
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001258 public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -07001259 int captureSession, int captureDelayMs, int capturePreambleMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001260 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
1261 @Nullable KeyphraseRecognitionExtra[] keyphraseExtras) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001262 super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
Eric Laurentd3b82232014-07-30 08:57:39 -07001263 capturePreambleMs, triggerInData, captureFormat, data);
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001264 this.keyphraseExtras =
1265 keyphraseExtras != null ? keyphraseExtras : new KeyphraseRecognitionExtra[0];
Eric Laurente48188c2014-04-18 17:44:11 -07001266 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001267
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001268 public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001269 = new Parcelable.Creator<KeyphraseRecognitionEvent>() {
1270 public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001271 return KeyphraseRecognitionEvent.fromParcelForKeyphrase(in);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001272 }
1273
1274 public KeyphraseRecognitionEvent[] newArray(int size) {
1275 return new KeyphraseRecognitionEvent[size];
1276 }
1277 };
1278
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001279 private static KeyphraseRecognitionEvent fromParcelForKeyphrase(Parcel in) {
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001280 int status = in.readInt();
1281 int soundModelHandle = in.readInt();
1282 boolean captureAvailable = in.readByte() == 1;
1283 int captureSession = in.readInt();
1284 int captureDelayMs = in.readInt();
1285 int capturePreambleMs = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -07001286 boolean triggerInData = in.readByte() == 1;
1287 AudioFormat captureFormat = null;
Eric Laurent75b433f2014-09-12 15:45:47 -07001288 if (in.readByte() == 1) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001289 int sampleRate = in.readInt();
1290 int encoding = in.readInt();
1291 int channelMask = in.readInt();
1292 captureFormat = (new AudioFormat.Builder())
Ryan Bavettaea04e8f2016-03-02 18:34:50 -08001293 .setChannelMask(channelMask)
1294 .setEncoding(encoding)
1295 .setSampleRate(sampleRate)
1296 .build();
Eric Laurentd3b82232014-07-30 08:57:39 -07001297 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001298 byte[] data = in.readBlob();
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001299 KeyphraseRecognitionExtra[] keyphraseExtras =
1300 in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
1301 return new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -07001302 captureSession, captureDelayMs, capturePreambleMs, triggerInData,
1303 captureFormat, data, keyphraseExtras);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001304 }
1305
1306 @Override
1307 public void writeToParcel(Parcel dest, int flags) {
1308 dest.writeInt(status);
1309 dest.writeInt(soundModelHandle);
1310 dest.writeByte((byte) (captureAvailable ? 1 : 0));
1311 dest.writeInt(captureSession);
1312 dest.writeInt(captureDelayMs);
1313 dest.writeInt(capturePreambleMs);
Eric Laurent75b433f2014-09-12 15:45:47 -07001314 dest.writeByte((byte) (triggerInData ? 1 : 0));
1315 if (captureFormat != null) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001316 dest.writeByte((byte)1);
1317 dest.writeInt(captureFormat.getSampleRate());
1318 dest.writeInt(captureFormat.getEncoding());
1319 dest.writeInt(captureFormat.getChannelMask());
1320 } else {
1321 dest.writeByte((byte)0);
1322 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001323 dest.writeBlob(data);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001324 dest.writeTypedArray(keyphraseExtras, flags);
1325 }
1326
1327 @Override
1328 public int describeContents() {
1329 return 0;
1330 }
1331
1332 @Override
1333 public int hashCode() {
1334 final int prime = 31;
1335 int result = super.hashCode();
1336 result = prime * result + Arrays.hashCode(keyphraseExtras);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001337 return result;
1338 }
1339
1340 @Override
1341 public boolean equals(Object obj) {
1342 if (this == obj)
1343 return true;
1344 if (!super.equals(obj))
1345 return false;
1346 if (getClass() != obj.getClass())
1347 return false;
1348 KeyphraseRecognitionEvent other = (KeyphraseRecognitionEvent) obj;
1349 if (!Arrays.equals(keyphraseExtras, other.keyphraseExtras))
1350 return false;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001351 return true;
1352 }
1353
1354 @Override
1355 public String toString() {
1356 return "KeyphraseRecognitionEvent [keyphraseExtras=" + Arrays.toString(keyphraseExtras)
Eric Laurentd3b82232014-07-30 08:57:39 -07001357 + ", status=" + status
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001358 + ", soundModelHandle=" + soundModelHandle + ", captureAvailable="
1359 + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs="
1360 + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs
Eric Laurentd3b82232014-07-30 08:57:39 -07001361 + ", triggerInData=" + triggerInData
1362 + ((captureFormat == null) ? "" :
1363 (", sampleRate=" + captureFormat.getSampleRate()))
1364 + ((captureFormat == null) ? "" :
1365 (", encoding=" + captureFormat.getEncoding()))
1366 + ((captureFormat == null) ? "" :
1367 (", channelMask=" + captureFormat.getChannelMask()))
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001368 + ", data=" + (data == null ? 0 : data.length) + "]";
1369 }
Eric Laurente48188c2014-04-18 17:44:11 -07001370 }
1371
1372 /**
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001373 * Sub-class of RecognitionEvent specifically for sound-trigger based sound
1374 * models(non-keyphrase). Currently does not contain any additional fields.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001375 *
1376 * @hide
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001377 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001378 public static class GenericRecognitionEvent extends RecognitionEvent implements Parcelable {
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001379 @UnsupportedAppUsage
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001380 public GenericRecognitionEvent(int status, int soundModelHandle,
1381 boolean captureAvailable, int captureSession, int captureDelayMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001382 int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat,
1383 @Nullable byte[] data) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001384 super(status, soundModelHandle, captureAvailable, captureSession,
1385 captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
1386 data);
1387 }
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001388
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001389 public static final @android.annotation.NonNull Parcelable.Creator<GenericRecognitionEvent> CREATOR
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001390 = new Parcelable.Creator<GenericRecognitionEvent>() {
1391 public GenericRecognitionEvent createFromParcel(Parcel in) {
1392 return GenericRecognitionEvent.fromParcelForGeneric(in);
1393 }
1394
1395 public GenericRecognitionEvent[] newArray(int size) {
1396 return new GenericRecognitionEvent[size];
1397 }
1398 };
1399
1400 private static GenericRecognitionEvent fromParcelForGeneric(Parcel in) {
1401 RecognitionEvent event = RecognitionEvent.fromParcel(in);
1402 return new GenericRecognitionEvent(event.status, event.soundModelHandle,
1403 event.captureAvailable, event.captureSession, event.captureDelayMs,
1404 event.capturePreambleMs, event.triggerInData, event.captureFormat, event.data);
1405 }
1406
1407 @Override
1408 public boolean equals(Object obj) {
1409 if (this == obj)
1410 return true;
1411 if (obj == null)
1412 return false;
1413 if (getClass() != obj.getClass()) return false;
1414 RecognitionEvent other = (RecognitionEvent) obj;
1415 return super.equals(obj);
1416 }
1417
1418 @Override
1419 public String toString() {
1420 return "GenericRecognitionEvent ::" + super.toString();
1421 }
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001422 }
1423
1424 /**
Eric Laurentd3b82232014-07-30 08:57:39 -07001425 * Status codes for {@link SoundModelEvent}
1426 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001427 /**
1428 * Sound Model was updated
1429 *
1430 * @hide
1431 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001432 public static final int SOUNDMODEL_STATUS_UPDATED = 0;
1433
1434 /**
1435 * A SoundModelEvent is provided by the
1436 * {@link StatusListener#onSoundModelUpdate(SoundModelEvent)}
1437 * callback when a sound model has been updated by the implementation
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001438 *
1439 * @hide
Eric Laurentd3b82232014-07-30 08:57:39 -07001440 */
1441 public static class SoundModelEvent implements Parcelable {
1442 /** Status e.g {@link #SOUNDMODEL_STATUS_UPDATED} */
1443 public final int status;
1444 /** The updated sound model handle */
1445 public final int soundModelHandle;
1446 /** New sound model data */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001447 @NonNull
Eric Laurentd3b82232014-07-30 08:57:39 -07001448 public final byte[] data;
1449
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001450 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001451 SoundModelEvent(int status, int soundModelHandle, @Nullable byte[] data) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001452 this.status = status;
1453 this.soundModelHandle = soundModelHandle;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001454 this.data = data != null ? data : new byte[0];
Eric Laurentd3b82232014-07-30 08:57:39 -07001455 }
1456
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001457 public static final @android.annotation.NonNull Parcelable.Creator<SoundModelEvent> CREATOR
Eric Laurentd3b82232014-07-30 08:57:39 -07001458 = new Parcelable.Creator<SoundModelEvent>() {
1459 public SoundModelEvent createFromParcel(Parcel in) {
1460 return SoundModelEvent.fromParcel(in);
1461 }
1462
1463 public SoundModelEvent[] newArray(int size) {
1464 return new SoundModelEvent[size];
1465 }
1466 };
1467
1468 private static SoundModelEvent fromParcel(Parcel in) {
1469 int status = in.readInt();
1470 int soundModelHandle = in.readInt();
1471 byte[] data = in.readBlob();
1472 return new SoundModelEvent(status, soundModelHandle, data);
1473 }
1474
1475 @Override
1476 public int describeContents() {
1477 return 0;
1478 }
1479
1480 @Override
1481 public void writeToParcel(Parcel dest, int flags) {
1482 dest.writeInt(status);
1483 dest.writeInt(soundModelHandle);
1484 dest.writeBlob(data);
1485 }
1486
1487 @Override
1488 public int hashCode() {
1489 final int prime = 31;
1490 int result = 1;
1491 result = prime * result + Arrays.hashCode(data);
1492 result = prime * result + soundModelHandle;
1493 result = prime * result + status;
1494 return result;
1495 }
1496
1497 @Override
1498 public boolean equals(Object obj) {
1499 if (this == obj)
1500 return true;
1501 if (obj == null)
1502 return false;
1503 if (getClass() != obj.getClass())
1504 return false;
1505 SoundModelEvent other = (SoundModelEvent) obj;
1506 if (!Arrays.equals(data, other.data))
1507 return false;
1508 if (soundModelHandle != other.soundModelHandle)
1509 return false;
1510 if (status != other.status)
1511 return false;
1512 return true;
1513 }
1514
1515 @Override
1516 public String toString() {
1517 return "SoundModelEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
1518 + ", data=" + (data == null ? 0 : data.length) + "]";
1519 }
1520 }
1521
1522 /**
1523 * Native service state. {@link StatusListener#onServiceStateChange(int)}
1524 */
1525 // Keep in sync with system/core/include/system/sound_trigger.h
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001526 /**
1527 * Sound trigger service is enabled
1528 *
1529 * @hide
1530 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001531 public static final int SERVICE_STATE_ENABLED = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001532 /**
1533 * Sound trigger service is disabled
1534 *
1535 * @hide
1536 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001537 public static final int SERVICE_STATE_DISABLED = 1;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001538 private static Object mServiceLock = new Object();
1539 private static ISoundTriggerMiddlewareService mService;
1540 /**
jiabin1f4b4dd2019-03-18 18:07:03 -07001541 * @return returns current package name.
1542 */
1543 static String getCurrentOpPackageName() {
1544 String packageName = ActivityThread.currentOpPackageName();
1545 if (packageName == null) {
1546 return "";
1547 }
1548 return packageName;
1549 }
1550
1551 /**
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001552 * Returns a list of descriptors for all hardware modules loaded.
Eric Laurente48188c2014-04-18 17:44:11 -07001553 * @param modules A ModuleProperties array where the list will be returned.
1554 * @return - {@link #STATUS_OK} in case of success
1555 * - {@link #STATUS_ERROR} in case of unspecified error
1556 * - {@link #STATUS_PERMISSION_DENIED} if the caller does not have system permission
1557 * - {@link #STATUS_NO_INIT} if the native service cannot be reached
1558 * - {@link #STATUS_BAD_VALUE} if modules is null
1559 * - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001560 *
1561 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001562 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001563 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001564 public static int listModules(@NonNull ArrayList<ModuleProperties> modules) {
1565 try {
1566 SoundTriggerModuleDescriptor[] descs = getService().listModules();
1567 modules.clear();
1568 modules.ensureCapacity(descs.length);
1569 for (SoundTriggerModuleDescriptor desc : descs) {
1570 modules.add(ConversionUtil.aidl2apiModuleDescriptor(desc));
1571 }
1572 return STATUS_OK;
1573 } catch (RemoteException e) {
1574 Log.e(TAG, "Exception caught", e);
1575 return STATUS_DEAD_OBJECT;
1576 }
jiabin1f4b4dd2019-03-18 18:07:03 -07001577 }
1578
1579 /**
Eric Laurente48188c2014-04-18 17:44:11 -07001580 * Get an interface on a hardware module to control sound models and recognition on
1581 * this module.
1582 * @param moduleId Sound module system identifier {@link ModuleProperties#id}. mandatory.
1583 * @param listener {@link StatusListener} interface. Mandatory.
1584 * @param handler the Handler that will receive the callabcks. Can be null if default handler
1585 * is OK.
1586 * @return a valid sound module in case of success or null in case of error.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001587 *
1588 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001589 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001590 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001591 public static @NonNull SoundTriggerModule attachModule(int moduleId,
1592 @NonNull StatusListener listener,
1593 @Nullable Handler handler) {
1594 Looper looper = handler != null ? handler.getLooper() : Looper.getMainLooper();
1595 try {
1596 return new SoundTriggerModule(getService(), moduleId, listener, looper);
1597 } catch (RemoteException e) {
1598 Log.e(TAG, "", e);
Eric Laurente48188c2014-04-18 17:44:11 -07001599 return null;
1600 }
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001601 }
1602
1603 private static ISoundTriggerMiddlewareService getService() {
1604 synchronized (mServiceLock) {
1605 while (true) {
1606 IBinder binder = null;
1607 try {
1608 binder =
1609 ServiceManager.getServiceOrThrow(
1610 Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE);
1611 binder.linkToDeath(() -> {
1612 synchronized (mServiceLock) {
1613 mService = null;
1614 }
1615 }, 0);
1616 mService = ISoundTriggerMiddlewareService.Stub.asInterface(binder);
1617 break;
1618 } catch (Exception e) {
1619 Log.e(TAG, "Failed to bind to soundtrigger service", e);
1620 }
1621 }
1622 return mService;
1623 }
1624
Eric Laurente48188c2014-04-18 17:44:11 -07001625 }
1626
1627 /**
1628 * Interface provided by the client application when attaching to a {@link SoundTriggerModule}
1629 * to received recognition and error notifications.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001630 *
1631 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001632 */
1633 public static interface StatusListener {
1634 /**
1635 * Called when recognition succeeds of fails
1636 */
1637 public abstract void onRecognition(RecognitionEvent event);
1638
1639 /**
Eric Laurentd3b82232014-07-30 08:57:39 -07001640 * Called when a sound model has been updated
1641 */
1642 public abstract void onSoundModelUpdate(SoundModelEvent event);
1643
1644 /**
1645 * Called when the sound trigger native service state changes.
1646 * @param state Native service state. One of {@link SoundTrigger#SERVICE_STATE_ENABLED},
1647 * {@link SoundTrigger#SERVICE_STATE_DISABLED}
1648 */
1649 public abstract void onServiceStateChange(int state);
1650
1651 /**
Eric Laurente48188c2014-04-18 17:44:11 -07001652 * Called when the sound trigger native service dies
1653 */
1654 public abstract void onServiceDied();
1655 }
1656}