blob: 6c44bdb48df4c914a5141a83b46df031f3ede2ba [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/**
Ytai Ben-Tsvic59b2802020-01-07 14:08:16 -080050 * The SoundTrigger class provides access to the service managing the sound trigger HAL.
Eric Laurente48188c2014-04-18 17:44:11 -070051 *
52 * @hide
53 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080054@SystemApi
Eric Laurente48188c2014-04-18 17:44:11 -070055public class SoundTrigger {
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080056 private static final String TAG = "SoundTrigger";
Eric Laurente48188c2014-04-18 17:44:11 -070057
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080058 private SoundTrigger() {
59 }
60
61 /**
62 * Status code used when the operation succeeded
63 */
Eric Laurente48188c2014-04-18 17:44:11 -070064 public static final int STATUS_OK = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080065 /** @hide */
Eric Laurente48188c2014-04-18 17:44:11 -070066 public static final int STATUS_ERROR = Integer.MIN_VALUE;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080067 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020068 public static final int STATUS_PERMISSION_DENIED = -EPERM;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080069 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020070 public static final int STATUS_NO_INIT = -ENODEV;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080071 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020072 public static final int STATUS_BAD_VALUE = -EINVAL;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080073 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020074 public static final int STATUS_DEAD_OBJECT = -EPIPE;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080075 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020076 public static final int STATUS_INVALID_OPERATION = -ENOSYS;
Eric Laurente48188c2014-04-18 17:44:11 -070077
78 /*****************************************************************************
79 * A ModuleProperties describes a given sound trigger hardware module
80 * managed by the native sound trigger service. Each module has a unique
81 * ID used to target any API call to this paricular module. Module
82 * properties are returned by listModules() method.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080083 *
Eric Laurente48188c2014-04-18 17:44:11 -070084 ****************************************************************************/
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070085 public static final class ModuleProperties implements Parcelable {
Eric Laurente48188c2014-04-18 17:44:11 -070086 /** Unique module ID provided by the native service */
87 public final int id;
88
89 /** human readable voice detection engine implementor */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070090 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -070091 public final String implementor;
92
93 /** human readable voice detection engine description */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070094 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -070095 public final String description;
96
97 /** Unique voice engine Id (changes with each version) */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070098 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -070099 public final UUID uuid;
100
101 /** Voice detection engine version */
102 public final int version;
103
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800104 /**
105 * String naming the architecture used for running the supported models.
106 * (eg. a platform running models on a DSP could implement this string to convey the DSP
107 * architecture used)
108 */
109 @NonNull
110 public final String supportedModelArch;
111
Eric Laurente48188c2014-04-18 17:44:11 -0700112 /** Maximum number of active sound models */
113 public final int maxSoundModels;
114
115 /** Maximum number of key phrases */
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700116 public final int maxKeyphrases;
Eric Laurente48188c2014-04-18 17:44:11 -0700117
118 /** Maximum number of users per key phrase */
119 public final int maxUsers;
120
121 /** Supported recognition modes (bit field, RECOGNITION_MODE_VOICE_TRIGGER ...) */
122 public final int recognitionModes;
123
124 /** Supports seamless transition to capture mode after recognition */
125 public final boolean supportsCaptureTransition;
126
127 /** Maximum buffering capacity in ms if supportsCaptureTransition() is true */
128 public final int maxBufferMs;
129
130 /** Supports capture by other use cases while detection is active */
131 public final boolean supportsConcurrentCapture;
132
133 /** Rated power consumption when detection is active with TDB silence/sound/speech ratio */
134 public final int powerConsumptionMw;
135
Eric Laurentd3b82232014-07-30 08:57:39 -0700136 /** Returns the trigger (key phrase) capture in the binary data of the
137 * recognition callback event */
138 public final boolean returnsTriggerInEvent;
139
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800140 ModuleProperties(int id, @NonNull String implementor, @NonNull String description,
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800141 @NonNull String uuid, int version, @NonNull String supportedModelArch,
142 int maxSoundModels, int maxKeyphrases, int maxUsers, int recognitionModes,
143 boolean supportsCaptureTransition, int maxBufferMs,
144 boolean supportsConcurrentCapture, int powerConsumptionMw,
145 boolean returnsTriggerInEvent) {
Eric Laurente48188c2014-04-18 17:44:11 -0700146 this.id = id;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800147 this.implementor = requireNonNull(implementor);
148 this.description = requireNonNull(description);
149 this.uuid = UUID.fromString(requireNonNull(uuid));
Eric Laurente48188c2014-04-18 17:44:11 -0700150 this.version = version;
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800151 this.supportedModelArch = requireNonNull(supportedModelArch);
Eric Laurente48188c2014-04-18 17:44:11 -0700152 this.maxSoundModels = maxSoundModels;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700153 this.maxKeyphrases = maxKeyphrases;
Eric Laurente48188c2014-04-18 17:44:11 -0700154 this.maxUsers = maxUsers;
155 this.recognitionModes = recognitionModes;
156 this.supportsCaptureTransition = supportsCaptureTransition;
157 this.maxBufferMs = maxBufferMs;
158 this.supportsConcurrentCapture = supportsConcurrentCapture;
159 this.powerConsumptionMw = powerConsumptionMw;
Eric Laurentd3b82232014-07-30 08:57:39 -0700160 this.returnsTriggerInEvent = returnsTriggerInEvent;
Eric Laurente48188c2014-04-18 17:44:11 -0700161 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700162
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700163 public static final @android.annotation.NonNull Parcelable.Creator<ModuleProperties> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700164 = new Parcelable.Creator<ModuleProperties>() {
165 public ModuleProperties createFromParcel(Parcel in) {
166 return ModuleProperties.fromParcel(in);
167 }
168
169 public ModuleProperties[] newArray(int size) {
170 return new ModuleProperties[size];
171 }
172 };
173
174 private static ModuleProperties fromParcel(Parcel in) {
175 int id = in.readInt();
176 String implementor = in.readString();
177 String description = in.readString();
178 String uuid = in.readString();
179 int version = in.readInt();
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800180 String supportedModelArch = in.readString();
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700181 int maxSoundModels = in.readInt();
182 int maxKeyphrases = in.readInt();
183 int maxUsers = in.readInt();
184 int recognitionModes = in.readInt();
185 boolean supportsCaptureTransition = in.readByte() == 1;
186 int maxBufferMs = in.readInt();
187 boolean supportsConcurrentCapture = in.readByte() == 1;
188 int powerConsumptionMw = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -0700189 boolean returnsTriggerInEvent = in.readByte() == 1;
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700190 return new ModuleProperties(id, implementor, description, uuid, version,
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800191 supportedModelArch, maxSoundModels, maxKeyphrases, maxUsers, recognitionModes,
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700192 supportsCaptureTransition, maxBufferMs, supportsConcurrentCapture,
Eric Laurentd3b82232014-07-30 08:57:39 -0700193 powerConsumptionMw, returnsTriggerInEvent);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700194 }
195
196 @Override
197 public void writeToParcel(Parcel dest, int flags) {
198 dest.writeInt(id);
199 dest.writeString(implementor);
200 dest.writeString(description);
201 dest.writeString(uuid.toString());
202 dest.writeInt(version);
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800203 dest.writeString(supportedModelArch);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700204 dest.writeInt(maxSoundModels);
205 dest.writeInt(maxKeyphrases);
206 dest.writeInt(maxUsers);
207 dest.writeInt(recognitionModes);
208 dest.writeByte((byte) (supportsCaptureTransition ? 1 : 0));
209 dest.writeInt(maxBufferMs);
210 dest.writeByte((byte) (supportsConcurrentCapture ? 1 : 0));
211 dest.writeInt(powerConsumptionMw);
Eric Laurentd3b82232014-07-30 08:57:39 -0700212 dest.writeByte((byte) (returnsTriggerInEvent ? 1 : 0));
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700213 }
214
215 @Override
216 public int describeContents() {
217 return 0;
218 }
219
220 @Override
221 public String toString() {
222 return "ModuleProperties [id=" + id + ", implementor=" + implementor + ", description="
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800223 + description + ", uuid=" + uuid + ", version=" + version
224 + " , supportedModelArch=" + supportedModelArch + ", maxSoundModels="
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700225 + maxSoundModels + ", maxKeyphrases=" + maxKeyphrases + ", maxUsers="
226 + maxUsers + ", recognitionModes=" + recognitionModes
227 + ", supportsCaptureTransition=" + supportsCaptureTransition + ", maxBufferMs="
228 + maxBufferMs + ", supportsConcurrentCapture=" + supportsConcurrentCapture
Eric Laurentd3b82232014-07-30 08:57:39 -0700229 + ", powerConsumptionMw=" + powerConsumptionMw
230 + ", returnsTriggerInEvent=" + returnsTriggerInEvent + "]";
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700231 }
Eric Laurente48188c2014-04-18 17:44:11 -0700232 }
233
234 /*****************************************************************************
235 * A SoundModel describes the attributes and contains the binary data used by the hardware
236 * implementation to detect a particular sound pattern.
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700237 * A specialized version {@link KeyphraseSoundModel} is defined for key phrase
Eric Laurente48188c2014-04-18 17:44:11 -0700238 * sound models.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800239 *
240 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -0700241 ****************************************************************************/
242 public static class SoundModel {
243 /** Undefined sound model type */
244 public static final int TYPE_UNKNOWN = -1;
245
246 /** Keyphrase sound model */
247 public static final int TYPE_KEYPHRASE = 0;
248
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800249 /**
250 * A generic sound model. Use this type only for non-keyphrase sound models such as
251 * ones that match a particular sound pattern.
252 */
253 public static final int TYPE_GENERIC_SOUND = 1;
254
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700255 /** Unique sound model identifier */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100256 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800257 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700258 public final UUID uuid;
259
Eric Laurente48188c2014-04-18 17:44:11 -0700260 /** Sound model type (e.g. TYPE_KEYPHRASE); */
261 public final int type;
262
Eric Laurentd3b82232014-07-30 08:57:39 -0700263 /** Unique sound model vendor identifier */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100264 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800265 @NonNull
Eric Laurentd3b82232014-07-30 08:57:39 -0700266 public final UUID vendorUuid;
267
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800268 /** vendor specific version number of the model */
269 public final int version;
270
Eric Laurente48188c2014-04-18 17:44:11 -0700271 /** Opaque data. For use by vendor implementation and enrollment application */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100272 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800273 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700274 public final byte[] data;
275
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800276 public SoundModel(@NonNull UUID uuid, @Nullable UUID vendorUuid, int type,
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800277 @Nullable byte[] data, int version) {
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800278 this.uuid = requireNonNull(uuid);
279 this.vendorUuid = vendorUuid != null ? vendorUuid : new UUID(0, 0);
Eric Laurente48188c2014-04-18 17:44:11 -0700280 this.type = type;
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800281 this.version = version;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800282 this.data = data != null ? data : new byte[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700283 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700284
285 @Override
286 public int hashCode() {
287 final int prime = 31;
288 int result = 1;
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800289 result = prime * result + version;
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700290 result = prime * result + Arrays.hashCode(data);
291 result = prime * result + type;
292 result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
293 result = prime * result + ((vendorUuid == null) ? 0 : vendorUuid.hashCode());
294 return result;
295 }
296
297 @Override
298 public boolean equals(Object obj) {
299 if (this == obj)
300 return true;
301 if (obj == null)
302 return false;
303 if (!(obj instanceof SoundModel))
304 return false;
305 SoundModel other = (SoundModel) obj;
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700306 if (type != other.type)
307 return false;
308 if (uuid == null) {
309 if (other.uuid != null)
310 return false;
311 } else if (!uuid.equals(other.uuid))
312 return false;
313 if (vendorUuid == null) {
314 if (other.vendorUuid != null)
315 return false;
316 } else if (!vendorUuid.equals(other.vendorUuid))
317 return false;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800318 if (!Arrays.equals(data, other.data))
319 return false;
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800320 if (version != other.version)
321 return false;
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700322 return true;
323 }
Eric Laurente48188c2014-04-18 17:44:11 -0700324 }
325
326 /*****************************************************************************
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700327 * A Keyphrase describes a key phrase that can be detected by a
328 * {@link KeyphraseSoundModel}
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800329 *
330 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -0700331 ****************************************************************************/
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700332 public static class Keyphrase implements Parcelable {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700333 /** Unique identifier for this keyphrase */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100334 @UnsupportedAppUsage
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700335 public final int id;
336
Eric Laurente48188c2014-04-18 17:44:11 -0700337 /** Recognition modes supported for this key phrase in the model */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100338 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700339 public final int recognitionModes;
340
341 /** Locale of the keyphrase. JAVA Locale string e.g en_US */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100342 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800343 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700344 public final String locale;
345
346 /** Key phrase text */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100347 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800348 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700349 public final String text;
350
Eric Laurent013f66b2014-07-06 16:35:00 -0700351 /** Users this key phrase has been trained for. countains sound trigger specific user IDs
352 * derived from system user IDs {@link android.os.UserHandle#getIdentifier()}. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100353 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800354 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -0700355 public final int[] users;
Eric Laurente48188c2014-04-18 17:44:11 -0700356
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100357 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800358 public Keyphrase(int id, int recognitionModes, @NonNull String locale, @NonNull String text,
359 @Nullable int[] users) {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700360 this.id = id;
Eric Laurente48188c2014-04-18 17:44:11 -0700361 this.recognitionModes = recognitionModes;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800362 this.locale = requireNonNull(locale);
363 this.text = requireNonNull(text);
364 this.users = users != null ? users : new int[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700365 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700366
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700367 public static final @android.annotation.NonNull Parcelable.Creator<Keyphrase> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700368 = new Parcelable.Creator<Keyphrase>() {
369 public Keyphrase createFromParcel(Parcel in) {
370 return Keyphrase.fromParcel(in);
371 }
372
373 public Keyphrase[] newArray(int size) {
374 return new Keyphrase[size];
375 }
376 };
377
378 private static Keyphrase fromParcel(Parcel in) {
379 int id = in.readInt();
380 int recognitionModes = in.readInt();
381 String locale = in.readString();
382 String text = in.readString();
383 int[] users = null;
384 int numUsers = in.readInt();
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700385 if (numUsers >= 0) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700386 users = new int[numUsers];
387 in.readIntArray(users);
388 }
389 return new Keyphrase(id, recognitionModes, locale, text, users);
390 }
391
392 @Override
393 public void writeToParcel(Parcel dest, int flags) {
394 dest.writeInt(id);
395 dest.writeInt(recognitionModes);
396 dest.writeString(locale);
397 dest.writeString(text);
398 if (users != null) {
399 dest.writeInt(users.length);
400 dest.writeIntArray(users);
401 } else {
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700402 dest.writeInt(-1);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700403 }
404 }
405
406 @Override
407 public int describeContents() {
408 return 0;
409 }
410
411 @Override
412 public int hashCode() {
413 final int prime = 31;
414 int result = 1;
415 result = prime * result + ((text == null) ? 0 : text.hashCode());
416 result = prime * result + id;
417 result = prime * result + ((locale == null) ? 0 : locale.hashCode());
418 result = prime * result + recognitionModes;
419 result = prime * result + Arrays.hashCode(users);
420 return result;
421 }
422
423 @Override
424 public boolean equals(Object obj) {
425 if (this == obj)
426 return true;
427 if (obj == null)
428 return false;
429 if (getClass() != obj.getClass())
430 return false;
431 Keyphrase other = (Keyphrase) obj;
432 if (text == null) {
433 if (other.text != null)
434 return false;
435 } else if (!text.equals(other.text))
436 return false;
437 if (id != other.id)
438 return false;
439 if (locale == null) {
440 if (other.locale != null)
441 return false;
442 } else if (!locale.equals(other.locale))
443 return false;
444 if (recognitionModes != other.recognitionModes)
445 return false;
446 if (!Arrays.equals(users, other.users))
447 return false;
448 return true;
449 }
450
451 @Override
452 public String toString() {
453 return "Keyphrase [id=" + id + ", recognitionModes=" + recognitionModes + ", locale="
454 + locale + ", text=" + text + ", users=" + Arrays.toString(users) + "]";
455 }
Eric Laurente48188c2014-04-18 17:44:11 -0700456 }
457
458 /*****************************************************************************
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700459 * A KeyphraseSoundModel is a specialized {@link SoundModel} for key phrases.
Eric Laurente48188c2014-04-18 17:44:11 -0700460 * It contains data needed by the hardware to detect a certain number of key phrases
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700461 * and the list of corresponding {@link Keyphrase} descriptors.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800462 *
463 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -0700464 ****************************************************************************/
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700465 public static class KeyphraseSoundModel extends SoundModel implements Parcelable {
Eric Laurente48188c2014-04-18 17:44:11 -0700466 /** Key phrases in this sound model */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100467 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800468 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700469 public final Keyphrase[] keyphrases; // keyword phrases in model
Eric Laurente48188c2014-04-18 17:44:11 -0700470
Eric Laurentd3b82232014-07-30 08:57:39 -0700471 public KeyphraseSoundModel(
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800472 @NonNull UUID uuid, @NonNull UUID vendorUuid, @Nullable byte[] data,
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800473 @Nullable Keyphrase[] keyphrases, int version) {
474 super(uuid, vendorUuid, TYPE_KEYPHRASE, data, version);
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800475 this.keyphrases = keyphrases != null ? keyphrases : new Keyphrase[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700476 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700477
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800478 @UnsupportedAppUsage
479 public KeyphraseSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
480 @Nullable byte[] data, @Nullable Keyphrase[] keyphrases) {
481 this(uuid, vendorUuid, data, keyphrases, -1);
482 }
483
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700484 public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseSoundModel> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700485 = new Parcelable.Creator<KeyphraseSoundModel>() {
486 public KeyphraseSoundModel createFromParcel(Parcel in) {
487 return KeyphraseSoundModel.fromParcel(in);
488 }
489
490 public KeyphraseSoundModel[] newArray(int size) {
491 return new KeyphraseSoundModel[size];
492 }
493 };
494
495 private static KeyphraseSoundModel fromParcel(Parcel in) {
496 UUID uuid = UUID.fromString(in.readString());
Eric Laurentd3b82232014-07-30 08:57:39 -0700497 UUID vendorUuid = null;
498 int length = in.readInt();
499 if (length >= 0) {
500 vendorUuid = UUID.fromString(in.readString());
501 }
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800502 int version = in.readInt();
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700503 byte[] data = in.readBlob();
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700504 Keyphrase[] keyphrases = in.createTypedArray(Keyphrase.CREATOR);
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800505 return new KeyphraseSoundModel(uuid, vendorUuid, data, keyphrases, version);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700506 }
507
508 @Override
509 public int describeContents() {
510 return 0;
511 }
512
513 @Override
514 public void writeToParcel(Parcel dest, int flags) {
515 dest.writeString(uuid.toString());
Eric Laurentd3b82232014-07-30 08:57:39 -0700516 if (vendorUuid == null) {
517 dest.writeInt(-1);
518 } else {
519 dest.writeInt(vendorUuid.toString().length());
520 dest.writeString(vendorUuid.toString());
521 }
Nicholas Ambur43970b52020-01-14 18:54:26 -0800522 dest.writeInt(version);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700523 dest.writeBlob(data);
Sandeep Siddhartha68173372014-07-28 13:25:30 -0700524 dest.writeTypedArray(keyphrases, flags);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700525 }
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700526
527 @Override
528 public String toString() {
Eric Laurentd3b82232014-07-30 08:57:39 -0700529 return "KeyphraseSoundModel [keyphrases=" + Arrays.toString(keyphrases)
530 + ", uuid=" + uuid + ", vendorUuid=" + vendorUuid
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800531 + ", type=" + type
532 + ", data=" + (data == null ? 0 : data.length)
533 + ", version=" + version + "]";
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700534 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700535
536 @Override
537 public int hashCode() {
538 final int prime = 31;
539 int result = super.hashCode();
540 result = prime * result + Arrays.hashCode(keyphrases);
541 return result;
542 }
543
544 @Override
545 public boolean equals(Object obj) {
546 if (this == obj)
547 return true;
548 if (!super.equals(obj))
549 return false;
550 if (!(obj instanceof KeyphraseSoundModel))
551 return false;
552 KeyphraseSoundModel other = (KeyphraseSoundModel) obj;
553 if (!Arrays.equals(keyphrases, other.keyphrases))
554 return false;
555 return true;
556 }
Eric Laurente48188c2014-04-18 17:44:11 -0700557 }
558
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800559
560 /*****************************************************************************
561 * A GenericSoundModel is a specialized {@link SoundModel} for non-voice sound
562 * patterns.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800563 *
564 * @hide
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800565 ****************************************************************************/
566 public static class GenericSoundModel extends SoundModel implements Parcelable {
567
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700568 public static final @android.annotation.NonNull Parcelable.Creator<GenericSoundModel> CREATOR
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800569 = new Parcelable.Creator<GenericSoundModel>() {
570 public GenericSoundModel createFromParcel(Parcel in) {
571 return GenericSoundModel.fromParcel(in);
572 }
573
574 public GenericSoundModel[] newArray(int size) {
575 return new GenericSoundModel[size];
576 }
577 };
578
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800579 public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
580 @Nullable byte[] data, int version) {
581 super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data, version);
582 }
583
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100584 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800585 public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
586 @Nullable byte[] data) {
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800587 this(uuid, vendorUuid, data, -1);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800588 }
589
590 @Override
591 public int describeContents() {
592 return 0;
593 }
594
595 private static GenericSoundModel fromParcel(Parcel in) {
596 UUID uuid = UUID.fromString(in.readString());
597 UUID vendorUuid = null;
598 int length = in.readInt();
599 if (length >= 0) {
600 vendorUuid = UUID.fromString(in.readString());
601 }
602 byte[] data = in.readBlob();
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800603 int version = in.readInt();
604 return new GenericSoundModel(uuid, vendorUuid, data, version);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800605 }
606
607 @Override
608 public void writeToParcel(Parcel dest, int flags) {
609 dest.writeString(uuid.toString());
610 if (vendorUuid == null) {
611 dest.writeInt(-1);
612 } else {
613 dest.writeInt(vendorUuid.toString().length());
614 dest.writeString(vendorUuid.toString());
615 }
616 dest.writeBlob(data);
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800617 dest.writeInt(version);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800618 }
619
620 @Override
621 public String toString() {
622 return "GenericSoundModel [uuid=" + uuid + ", vendorUuid=" + vendorUuid
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800623 + ", type=" + type
624 + ", data=" + (data == null ? 0 : data.length)
625 + ", version=" + version + "]";
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800626 }
627 }
628
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800629 /**
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700630 * A ModelParamRange is a representation of supported parameter range for a
631 * given loaded model.
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800632 */
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700633 public static final class ModelParamRange implements Parcelable {
634
635 /**
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800636 * The inclusive start of supported range.
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700637 */
638 public final int start;
639
640 /**
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800641 * The inclusive end of supported range.
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700642 */
643 public final int end;
644
645 ModelParamRange(int start, int end) {
646 this.start = start;
647 this.end = end;
648 }
649
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800650 /** @hide */
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700651 private ModelParamRange(@NonNull Parcel in) {
652 this.start = in.readInt();
653 this.end = in.readInt();
654 }
655
656 @NonNull
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800657 public static final Creator<ModelParamRange> CREATOR =
658 new Creator<ModelParamRange>() {
659 @Override
660 @NonNull
661 public ModelParamRange createFromParcel(@NonNull Parcel in) {
662 return new ModelParamRange(in);
663 }
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700664
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800665 @Override
666 @NonNull
667 public ModelParamRange[] newArray(int size) {
668 return new ModelParamRange[size];
669 }
670 };
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700671
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800672 /** @hide */
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700673 @Override
674 public int describeContents() {
675 return 0;
676 }
677
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800678 /** @hide */
679 @Override
680 public int hashCode() {
681 final int prime = 31;
682 int result = 1;
683 result = prime * result + (start);
684 result = prime * result + (end);
685 return result;
686 }
687
688 @Override
689 public boolean equals(@Nullable Object obj) {
690 if (this == obj) {
691 return true;
692 }
693 if (obj == null) {
694 return false;
695 }
696 if (getClass() != obj.getClass()) {
697 return false;
698 }
699 ModelParamRange other = (ModelParamRange) obj;
700 if (start != other.start) {
701 return false;
702 }
703 if (end != other.end) {
704 return false;
705 }
706 return true;
707 }
708
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700709 @Override
710 public void writeToParcel(@NonNull Parcel dest, int flags) {
711 dest.writeInt(start);
712 dest.writeInt(end);
713 }
714
715 @Override
716 @NonNull
717 public String toString() {
718 return "ModelParamRange [start=" + start + ", end=" + end + "]";
719 }
720 }
721
Eric Laurente48188c2014-04-18 17:44:11 -0700722 /**
723 * Modes for key phrase recognition
724 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800725
726 /**
727 * Simple recognition of the key phrase
728 *
729 * @hide
730 */
Eric Laurente48188c2014-04-18 17:44:11 -0700731 public static final int RECOGNITION_MODE_VOICE_TRIGGER = 0x1;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800732 /**
733 * Trigger only if one user is identified
734 *
735 * @hide
736 */
Eric Laurente48188c2014-04-18 17:44:11 -0700737 public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 0x2;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800738 /**
739 * Trigger only if one user is authenticated
740 *
741 * @hide
742 */
Eric Laurente48188c2014-04-18 17:44:11 -0700743 public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 0x4;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800744 /**
745 * Generic (non-speech) recognition.
746 *
747 * @hide
748 */
749 public static final int RECOGNITION_MODE_GENERIC = 0x8;
Eric Laurente48188c2014-04-18 17:44:11 -0700750
751 /**
752 * Status codes for {@link RecognitionEvent}
753 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800754 /**
755 * Recognition success
756 *
757 * @hide
758 */
Eric Laurente48188c2014-04-18 17:44:11 -0700759 public static final int RECOGNITION_STATUS_SUCCESS = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800760 /**
761 * Recognition aborted (e.g. capture preempted by anotehr use case
762 *
763 * @hide
764 */
Eric Laurente48188c2014-04-18 17:44:11 -0700765 public static final int RECOGNITION_STATUS_ABORT = 1;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800766 /**
767 * Recognition failure
768 *
769 * @hide
770 */
Eric Laurente48188c2014-04-18 17:44:11 -0700771 public static final int RECOGNITION_STATUS_FAILURE = 2;
mike dooleyb2ab04a2018-11-07 15:48:54 +0100772 /**
773 * Recognition event was triggered by a getModelState request, not by the
774 * DSP.
775 *
776 * @hide
777 */
778 public static final int RECOGNITION_STATUS_GET_STATE_RESPONSE = 3;
Eric Laurente48188c2014-04-18 17:44:11 -0700779
780 /**
781 * A RecognitionEvent is provided by the
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800782 * {@code StatusListener#onRecognition(RecognitionEvent)}
Eric Laurente48188c2014-04-18 17:44:11 -0700783 * callback upon recognition success or failure.
784 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800785 public static class RecognitionEvent {
786 /**
787 * Recognition status e.g RECOGNITION_STATUS_SUCCESS
788 *
789 * @hide
790 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100791 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700792 public final int status;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800793 /**
794 *
795 * Sound Model corresponding to this event callback
796 *
797 * @hide
798 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100799 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700800 public final int soundModelHandle;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800801 /**
802 * True if it is possible to capture audio from this utterance buffered by the hardware
803 *
804 * @hide
805 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100806 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700807 public final boolean captureAvailable;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800808 /**
809 * Audio session ID to be used when capturing the utterance with an AudioRecord
810 * if captureAvailable() is true.
811 *
812 * @hide
813 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100814 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700815 public final int captureSession;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800816 /**
817 * Delay in ms between end of model detection and start of audio available for capture.
818 * A negative value is possible (e.g. if keyphrase is also available for capture)
819 *
820 * @hide
821 */
Eric Laurente48188c2014-04-18 17:44:11 -0700822 public final int captureDelayMs;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800823 /**
824 * Duration in ms of audio captured before the start of the trigger. 0 if none.
825 *
826 * @hide
827 */
Eric Laurent013f66b2014-07-06 16:35:00 -0700828 public final int capturePreambleMs;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800829 /**
830 * True if the trigger (key phrase capture is present in binary data
831 *
832 * @hide
833 */
Eric Laurentd3b82232014-07-30 08:57:39 -0700834 public final boolean triggerInData;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800835 /**
836 * Audio format of either the trigger in event data or to use for capture of the
837 * rest of the utterance
838 *
839 * @hide
840 */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800841 @NonNull
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800842 public final AudioFormat captureFormat;
843 /**
844 * Opaque data for use by system applications who know about voice engine internals,
845 * typically during enrollment.
846 *
847 * @hide
848 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100849 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800850 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700851 public final byte[] data;
852
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800853 /** @hide */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100854 @UnsupportedAppUsage
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700855 public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -0700856 int captureSession, int captureDelayMs, int capturePreambleMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800857 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) {
Eric Laurente48188c2014-04-18 17:44:11 -0700858 this.status = status;
859 this.soundModelHandle = soundModelHandle;
860 this.captureAvailable = captureAvailable;
861 this.captureSession = captureSession;
862 this.captureDelayMs = captureDelayMs;
Eric Laurent013f66b2014-07-06 16:35:00 -0700863 this.capturePreambleMs = capturePreambleMs;
Eric Laurentd3b82232014-07-30 08:57:39 -0700864 this.triggerInData = triggerInData;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800865 this.captureFormat = requireNonNull(captureFormat);
866 this.data = data != null ? data : new byte[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700867 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700868
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800869 /**
870 * Check if is possible to capture audio from this utterance buffered by the hardware.
871 *
872 * @return {@code true} iff a capturing is possible
873 */
874 public boolean isCaptureAvailable() {
875 return captureAvailable;
876 }
877
878 /**
879 * Get the audio format of either the trigger in event data or to use for capture of the
880 * rest of the utterance
881 *
882 * @return the audio format
883 */
884 @Nullable public AudioFormat getCaptureFormat() {
885 return captureFormat;
886 }
887
888 /**
889 * Get Audio session ID to be used when capturing the utterance with an {@link AudioRecord}
890 * if {@link #isCaptureAvailable()} is true.
891 *
892 * @return The id of the capture session
893 */
894 public int getCaptureSession() {
895 return captureSession;
896 }
897
898 /**
899 * Get the opaque data for use by system applications who know about voice engine
900 * internals, typically during enrollment.
901 *
902 * @return The data of the event
903 */
904 public byte[] getData() {
905 return data;
906 }
907
908 /** @hide */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700909 public static final @android.annotation.NonNull Parcelable.Creator<RecognitionEvent> CREATOR
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700910 = new Parcelable.Creator<RecognitionEvent>() {
911 public RecognitionEvent createFromParcel(Parcel in) {
912 return RecognitionEvent.fromParcel(in);
913 }
914
915 public RecognitionEvent[] newArray(int size) {
916 return new RecognitionEvent[size];
917 }
918 };
919
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800920 /** @hide */
Arunesh Mishraf47f1732016-02-18 16:16:12 -0800921 protected static RecognitionEvent fromParcel(Parcel in) {
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700922 int status = in.readInt();
923 int soundModelHandle = in.readInt();
924 boolean captureAvailable = in.readByte() == 1;
925 int captureSession = in.readInt();
926 int captureDelayMs = in.readInt();
927 int capturePreambleMs = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -0700928 boolean triggerInData = in.readByte() == 1;
929 AudioFormat captureFormat = null;
Eric Laurent39fcca02014-09-05 16:44:19 -0700930 if (in.readByte() == 1) {
Eric Laurentd3b82232014-07-30 08:57:39 -0700931 int sampleRate = in.readInt();
932 int encoding = in.readInt();
933 int channelMask = in.readInt();
934 captureFormat = (new AudioFormat.Builder())
935 .setChannelMask(channelMask)
936 .setEncoding(encoding)
937 .setSampleRate(sampleRate)
938 .build();
939 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700940 byte[] data = in.readBlob();
941 return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession,
Eric Laurentd3b82232014-07-30 08:57:39 -0700942 captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700943 }
944
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800945 /** @hide */
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700946 public int describeContents() {
947 return 0;
948 }
949
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800950 /** @hide */
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700951 public void writeToParcel(Parcel dest, int flags) {
952 dest.writeInt(status);
953 dest.writeInt(soundModelHandle);
954 dest.writeByte((byte) (captureAvailable ? 1 : 0));
955 dest.writeInt(captureSession);
956 dest.writeInt(captureDelayMs);
957 dest.writeInt(capturePreambleMs);
Eric Laurent39fcca02014-09-05 16:44:19 -0700958 dest.writeByte((byte) (triggerInData ? 1 : 0));
959 if (captureFormat != null) {
Eric Laurentd3b82232014-07-30 08:57:39 -0700960 dest.writeByte((byte)1);
961 dest.writeInt(captureFormat.getSampleRate());
962 dest.writeInt(captureFormat.getEncoding());
963 dest.writeInt(captureFormat.getChannelMask());
964 } else {
965 dest.writeByte((byte)0);
966 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700967 dest.writeBlob(data);
968 }
969
970 @Override
971 public int hashCode() {
972 final int prime = 31;
973 int result = 1;
974 result = prime * result + (captureAvailable ? 1231 : 1237);
975 result = prime * result + captureDelayMs;
976 result = prime * result + capturePreambleMs;
977 result = prime * result + captureSession;
Eric Laurentd3b82232014-07-30 08:57:39 -0700978 result = prime * result + (triggerInData ? 1231 : 1237);
979 if (captureFormat != null) {
980 result = prime * result + captureFormat.getSampleRate();
981 result = prime * result + captureFormat.getEncoding();
982 result = prime * result + captureFormat.getChannelMask();
983 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700984 result = prime * result + Arrays.hashCode(data);
985 result = prime * result + soundModelHandle;
986 result = prime * result + status;
987 return result;
988 }
989
990 @Override
Aurimas Liutikas4d1699d2019-08-28 13:01:05 -0700991 public boolean equals(@Nullable Object obj) {
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700992 if (this == obj)
993 return true;
994 if (obj == null)
995 return false;
996 if (getClass() != obj.getClass())
997 return false;
998 RecognitionEvent other = (RecognitionEvent) obj;
999 if (captureAvailable != other.captureAvailable)
1000 return false;
1001 if (captureDelayMs != other.captureDelayMs)
1002 return false;
1003 if (capturePreambleMs != other.capturePreambleMs)
1004 return false;
1005 if (captureSession != other.captureSession)
1006 return false;
1007 if (!Arrays.equals(data, other.data))
1008 return false;
1009 if (soundModelHandle != other.soundModelHandle)
1010 return false;
1011 if (status != other.status)
1012 return false;
Eric Laurentd3b82232014-07-30 08:57:39 -07001013 if (triggerInData != other.triggerInData)
1014 return false;
Ryan Bavettaea04e8f2016-03-02 18:34:50 -08001015 if (captureFormat == null) {
1016 if (other.captureFormat != null)
1017 return false;
1018 } else {
1019 if (other.captureFormat == null)
1020 return false;
1021 if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
1022 return false;
1023 if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
1024 return false;
1025 if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
1026 return false;
1027 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001028 return true;
1029 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001030
Aurimas Liutikas4d1699d2019-08-28 13:01:05 -07001031 @NonNull
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001032 @Override
1033 public String toString() {
1034 return "RecognitionEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
1035 + ", captureAvailable=" + captureAvailable + ", captureSession="
1036 + captureSession + ", captureDelayMs=" + captureDelayMs
1037 + ", capturePreambleMs=" + capturePreambleMs
Eric Laurentd3b82232014-07-30 08:57:39 -07001038 + ", triggerInData=" + triggerInData
1039 + ((captureFormat == null) ? "" :
1040 (", sampleRate=" + captureFormat.getSampleRate()))
1041 + ((captureFormat == null) ? "" :
1042 (", encoding=" + captureFormat.getEncoding()))
1043 + ((captureFormat == null) ? "" :
1044 (", channelMask=" + captureFormat.getChannelMask()))
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001045 + ", data=" + (data == null ? 0 : data.length) + "]";
1046 }
Eric Laurente48188c2014-04-18 17:44:11 -07001047 }
1048
1049 /**
Eric Laurent013f66b2014-07-06 16:35:00 -07001050 * A RecognitionConfig is provided to
1051 * {@link SoundTriggerModule#startRecognition(int, RecognitionConfig)} to configure the
1052 * recognition request.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001053 *
1054 * @hide
Eric Laurent013f66b2014-07-06 16:35:00 -07001055 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001056 public static class RecognitionConfig implements Parcelable {
Eric Laurent013f66b2014-07-06 16:35:00 -07001057 /** True if the DSP should capture the trigger sound and make it available for further
1058 * capture. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001059 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001060 public final boolean captureRequested;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001061 /**
1062 * True if the service should restart listening after the DSP triggers.
1063 * Note: This config flag is currently used at the service layer rather than by the DSP.
1064 */
1065 public final boolean allowMultipleTriggers;
Eric Laurent013f66b2014-07-06 16:35:00 -07001066 /** List of all keyphrases in the sound model for which recognition should be performed with
1067 * options for each keyphrase. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001068 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001069 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -07001070 public final KeyphraseRecognitionExtra keyphrases[];
1071 /** Opaque data for use by system applications who know about voice engine internals,
1072 * typically during enrollment. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001073 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001074 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -07001075 public final byte[] data;
1076
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001077 @UnsupportedAppUsage
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001078 public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001079 @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001080 this.captureRequested = captureRequested;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001081 this.allowMultipleTriggers = allowMultipleTriggers;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001082 this.keyphrases = keyphrases != null ? keyphrases : new KeyphraseRecognitionExtra[0];
1083 this.data = data != null ? data : new byte[0];
Eric Laurent013f66b2014-07-06 16:35:00 -07001084 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001085
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001086 public static final @android.annotation.NonNull Parcelable.Creator<RecognitionConfig> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001087 = new Parcelable.Creator<RecognitionConfig>() {
1088 public RecognitionConfig createFromParcel(Parcel in) {
1089 return RecognitionConfig.fromParcel(in);
1090 }
1091
1092 public RecognitionConfig[] newArray(int size) {
1093 return new RecognitionConfig[size];
1094 }
1095 };
1096
1097 private static RecognitionConfig fromParcel(Parcel in) {
1098 boolean captureRequested = in.readByte() == 1;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001099 boolean allowMultipleTriggers = in.readByte() == 1;
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001100 KeyphraseRecognitionExtra[] keyphrases =
1101 in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001102 byte[] data = in.readBlob();
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001103 return new RecognitionConfig(captureRequested, allowMultipleTriggers, keyphrases, data);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001104 }
1105
1106 @Override
1107 public void writeToParcel(Parcel dest, int flags) {
1108 dest.writeByte((byte) (captureRequested ? 1 : 0));
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001109 dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0));
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001110 dest.writeTypedArray(keyphrases, flags);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001111 dest.writeBlob(data);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001112 }
1113
1114 @Override
1115 public int describeContents() {
1116 return 0;
1117 }
Sandeep Siddhartha110f5692014-07-20 12:22:56 -07001118
1119 @Override
1120 public String toString() {
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001121 return "RecognitionConfig [captureRequested=" + captureRequested
1122 + ", allowMultipleTriggers=" + allowMultipleTriggers + ", keyphrases="
1123 + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data) + "]";
Sandeep Siddhartha110f5692014-07-20 12:22:56 -07001124 }
Eric Laurent013f66b2014-07-06 16:35:00 -07001125 }
1126
1127 /**
1128 * Confidence level for users defined in a keyphrase.
1129 * - The confidence level is expressed in percent (0% -100%).
1130 * When used in a {@link KeyphraseRecognitionEvent} it indicates the detected confidence level
1131 * When used in a {@link RecognitionConfig} it indicates the minimum confidence level that
1132 * should trigger a recognition.
1133 * - The user ID is derived from the system ID {@link android.os.UserHandle#getIdentifier()}.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001134 *
1135 * @hide
Eric Laurent013f66b2014-07-06 16:35:00 -07001136 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001137 public static class ConfidenceLevel implements Parcelable {
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001138 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001139 public final int userId;
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001140 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001141 public final int confidenceLevel;
1142
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001143 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001144 public ConfidenceLevel(int userId, int confidenceLevel) {
1145 this.userId = userId;
1146 this.confidenceLevel = confidenceLevel;
1147 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001148
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001149 public static final @android.annotation.NonNull Parcelable.Creator<ConfidenceLevel> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001150 = new Parcelable.Creator<ConfidenceLevel>() {
1151 public ConfidenceLevel createFromParcel(Parcel in) {
1152 return ConfidenceLevel.fromParcel(in);
1153 }
1154
1155 public ConfidenceLevel[] newArray(int size) {
1156 return new ConfidenceLevel[size];
1157 }
1158 };
1159
1160 private static ConfidenceLevel fromParcel(Parcel in) {
1161 int userId = in.readInt();
1162 int confidenceLevel = in.readInt();
1163 return new ConfidenceLevel(userId, confidenceLevel);
1164 }
1165
1166 @Override
1167 public void writeToParcel(Parcel dest, int flags) {
1168 dest.writeInt(userId);
1169 dest.writeInt(confidenceLevel);
1170 }
1171
1172 @Override
1173 public int describeContents() {
1174 return 0;
1175 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001176
1177 @Override
1178 public int hashCode() {
1179 final int prime = 31;
1180 int result = 1;
1181 result = prime * result + confidenceLevel;
1182 result = prime * result + userId;
1183 return result;
1184 }
1185
1186 @Override
1187 public boolean equals(Object obj) {
1188 if (this == obj)
1189 return true;
1190 if (obj == null)
1191 return false;
1192 if (getClass() != obj.getClass())
1193 return false;
1194 ConfidenceLevel other = (ConfidenceLevel) obj;
1195 if (confidenceLevel != other.confidenceLevel)
1196 return false;
1197 if (userId != other.userId)
1198 return false;
1199 return true;
1200 }
1201
1202 @Override
1203 public String toString() {
1204 return "ConfidenceLevel [userId=" + userId
1205 + ", confidenceLevel=" + confidenceLevel + "]";
1206 }
Eric Laurent013f66b2014-07-06 16:35:00 -07001207 }
1208
1209 /**
Sandeep Siddharthad4233c62014-06-12 18:31:19 -07001210 * Additional data conveyed by a {@link KeyphraseRecognitionEvent}
Eric Laurente48188c2014-04-18 17:44:11 -07001211 * for a key phrase detection.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001212 *
1213 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001214 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001215 public static class KeyphraseRecognitionExtra implements Parcelable {
1216 /** The keyphrase ID */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001217 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001218 public final int id;
Eric Laurente48188c2014-04-18 17:44:11 -07001219
1220 /** Recognition modes matched for this event */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001221 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -07001222 public final int recognitionModes;
1223
Eric Laurentd3b82232014-07-30 08:57:39 -07001224 /** Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
1225 * is not performed */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001226 @UnsupportedAppUsage
Eric Laurentd3b82232014-07-30 08:57:39 -07001227 public final int coarseConfidenceLevel;
1228
Eric Laurent013f66b2014-07-06 16:35:00 -07001229 /** Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to
1230 * be recognized (RecognitionConfig) */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001231 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001232 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -07001233 public final ConfidenceLevel[] confidenceLevels;
1234
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001235 @UnsupportedAppUsage
Eric Laurentd3b82232014-07-30 08:57:39 -07001236 public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001237 @Nullable ConfidenceLevel[] confidenceLevels) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001238 this.id = id;
Eric Laurente48188c2014-04-18 17:44:11 -07001239 this.recognitionModes = recognitionModes;
Eric Laurentd3b82232014-07-30 08:57:39 -07001240 this.coarseConfidenceLevel = coarseConfidenceLevel;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001241 this.confidenceLevels =
1242 confidenceLevels != null ? confidenceLevels : new ConfidenceLevel[0];
Eric Laurente48188c2014-04-18 17:44:11 -07001243 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001244
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001245 public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionExtra> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001246 = new Parcelable.Creator<KeyphraseRecognitionExtra>() {
1247 public KeyphraseRecognitionExtra createFromParcel(Parcel in) {
1248 return KeyphraseRecognitionExtra.fromParcel(in);
1249 }
1250
1251 public KeyphraseRecognitionExtra[] newArray(int size) {
1252 return new KeyphraseRecognitionExtra[size];
1253 }
1254 };
1255
1256 private static KeyphraseRecognitionExtra fromParcel(Parcel in) {
1257 int id = in.readInt();
1258 int recognitionModes = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -07001259 int coarseConfidenceLevel = in.readInt();
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001260 ConfidenceLevel[] confidenceLevels = in.createTypedArray(ConfidenceLevel.CREATOR);
Eric Laurentd3b82232014-07-30 08:57:39 -07001261 return new KeyphraseRecognitionExtra(id, recognitionModes, coarseConfidenceLevel,
1262 confidenceLevels);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001263 }
1264
1265 @Override
1266 public void writeToParcel(Parcel dest, int flags) {
1267 dest.writeInt(id);
1268 dest.writeInt(recognitionModes);
Eric Laurentd3b82232014-07-30 08:57:39 -07001269 dest.writeInt(coarseConfidenceLevel);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001270 dest.writeTypedArray(confidenceLevels, flags);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001271 }
1272
1273 @Override
1274 public int describeContents() {
1275 return 0;
1276 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001277
1278 @Override
1279 public int hashCode() {
1280 final int prime = 31;
1281 int result = 1;
1282 result = prime * result + Arrays.hashCode(confidenceLevels);
1283 result = prime * result + id;
1284 result = prime * result + recognitionModes;
Eric Laurentd3b82232014-07-30 08:57:39 -07001285 result = prime * result + coarseConfidenceLevel;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001286 return result;
1287 }
1288
1289 @Override
1290 public boolean equals(Object obj) {
1291 if (this == obj)
1292 return true;
1293 if (obj == null)
1294 return false;
1295 if (getClass() != obj.getClass())
1296 return false;
1297 KeyphraseRecognitionExtra other = (KeyphraseRecognitionExtra) obj;
1298 if (!Arrays.equals(confidenceLevels, other.confidenceLevels))
1299 return false;
1300 if (id != other.id)
1301 return false;
1302 if (recognitionModes != other.recognitionModes)
1303 return false;
Eric Laurentd3b82232014-07-30 08:57:39 -07001304 if (coarseConfidenceLevel != other.coarseConfidenceLevel)
1305 return false;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001306 return true;
1307 }
1308
1309 @Override
1310 public String toString() {
1311 return "KeyphraseRecognitionExtra [id=" + id + ", recognitionModes=" + recognitionModes
Eric Laurentd3b82232014-07-30 08:57:39 -07001312 + ", coarseConfidenceLevel=" + coarseConfidenceLevel
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001313 + ", confidenceLevels=" + Arrays.toString(confidenceLevels) + "]";
1314 }
Eric Laurente48188c2014-04-18 17:44:11 -07001315 }
1316
1317 /**
1318 * Specialized {@link RecognitionEvent} for a key phrase detection.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001319 *
1320 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001321 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001322 public static class KeyphraseRecognitionEvent extends RecognitionEvent implements Parcelable {
Eric Laurente48188c2014-04-18 17:44:11 -07001323 /** Indicates if the key phrase is present in the buffered audio available for capture */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001324 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001325 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -07001326 public final KeyphraseRecognitionExtra[] keyphraseExtras;
Eric Laurente48188c2014-04-18 17:44:11 -07001327
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001328 @UnsupportedAppUsage
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001329 public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -07001330 int captureSession, int captureDelayMs, int capturePreambleMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001331 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
1332 @Nullable KeyphraseRecognitionExtra[] keyphraseExtras) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001333 super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
Eric Laurentd3b82232014-07-30 08:57:39 -07001334 capturePreambleMs, triggerInData, captureFormat, data);
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001335 this.keyphraseExtras =
1336 keyphraseExtras != null ? keyphraseExtras : new KeyphraseRecognitionExtra[0];
Eric Laurente48188c2014-04-18 17:44:11 -07001337 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001338
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001339 public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001340 = new Parcelable.Creator<KeyphraseRecognitionEvent>() {
1341 public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001342 return KeyphraseRecognitionEvent.fromParcelForKeyphrase(in);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001343 }
1344
1345 public KeyphraseRecognitionEvent[] newArray(int size) {
1346 return new KeyphraseRecognitionEvent[size];
1347 }
1348 };
1349
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001350 private static KeyphraseRecognitionEvent fromParcelForKeyphrase(Parcel in) {
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001351 int status = in.readInt();
1352 int soundModelHandle = in.readInt();
1353 boolean captureAvailable = in.readByte() == 1;
1354 int captureSession = in.readInt();
1355 int captureDelayMs = in.readInt();
1356 int capturePreambleMs = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -07001357 boolean triggerInData = in.readByte() == 1;
1358 AudioFormat captureFormat = null;
Eric Laurent75b433f2014-09-12 15:45:47 -07001359 if (in.readByte() == 1) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001360 int sampleRate = in.readInt();
1361 int encoding = in.readInt();
1362 int channelMask = in.readInt();
1363 captureFormat = (new AudioFormat.Builder())
Ryan Bavettaea04e8f2016-03-02 18:34:50 -08001364 .setChannelMask(channelMask)
1365 .setEncoding(encoding)
1366 .setSampleRate(sampleRate)
1367 .build();
Eric Laurentd3b82232014-07-30 08:57:39 -07001368 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001369 byte[] data = in.readBlob();
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001370 KeyphraseRecognitionExtra[] keyphraseExtras =
1371 in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
1372 return new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -07001373 captureSession, captureDelayMs, capturePreambleMs, triggerInData,
1374 captureFormat, data, keyphraseExtras);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001375 }
1376
1377 @Override
1378 public void writeToParcel(Parcel dest, int flags) {
1379 dest.writeInt(status);
1380 dest.writeInt(soundModelHandle);
1381 dest.writeByte((byte) (captureAvailable ? 1 : 0));
1382 dest.writeInt(captureSession);
1383 dest.writeInt(captureDelayMs);
1384 dest.writeInt(capturePreambleMs);
Eric Laurent75b433f2014-09-12 15:45:47 -07001385 dest.writeByte((byte) (triggerInData ? 1 : 0));
1386 if (captureFormat != null) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001387 dest.writeByte((byte)1);
1388 dest.writeInt(captureFormat.getSampleRate());
1389 dest.writeInt(captureFormat.getEncoding());
1390 dest.writeInt(captureFormat.getChannelMask());
1391 } else {
1392 dest.writeByte((byte)0);
1393 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001394 dest.writeBlob(data);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001395 dest.writeTypedArray(keyphraseExtras, flags);
1396 }
1397
1398 @Override
1399 public int describeContents() {
1400 return 0;
1401 }
1402
1403 @Override
1404 public int hashCode() {
1405 final int prime = 31;
1406 int result = super.hashCode();
1407 result = prime * result + Arrays.hashCode(keyphraseExtras);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001408 return result;
1409 }
1410
1411 @Override
1412 public boolean equals(Object obj) {
1413 if (this == obj)
1414 return true;
1415 if (!super.equals(obj))
1416 return false;
1417 if (getClass() != obj.getClass())
1418 return false;
1419 KeyphraseRecognitionEvent other = (KeyphraseRecognitionEvent) obj;
1420 if (!Arrays.equals(keyphraseExtras, other.keyphraseExtras))
1421 return false;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001422 return true;
1423 }
1424
1425 @Override
1426 public String toString() {
1427 return "KeyphraseRecognitionEvent [keyphraseExtras=" + Arrays.toString(keyphraseExtras)
Eric Laurentd3b82232014-07-30 08:57:39 -07001428 + ", status=" + status
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001429 + ", soundModelHandle=" + soundModelHandle + ", captureAvailable="
1430 + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs="
1431 + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs
Eric Laurentd3b82232014-07-30 08:57:39 -07001432 + ", triggerInData=" + triggerInData
1433 + ((captureFormat == null) ? "" :
1434 (", sampleRate=" + captureFormat.getSampleRate()))
1435 + ((captureFormat == null) ? "" :
1436 (", encoding=" + captureFormat.getEncoding()))
1437 + ((captureFormat == null) ? "" :
1438 (", channelMask=" + captureFormat.getChannelMask()))
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001439 + ", data=" + (data == null ? 0 : data.length) + "]";
1440 }
Eric Laurente48188c2014-04-18 17:44:11 -07001441 }
1442
1443 /**
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001444 * Sub-class of RecognitionEvent specifically for sound-trigger based sound
1445 * models(non-keyphrase). Currently does not contain any additional fields.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001446 *
1447 * @hide
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001448 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001449 public static class GenericRecognitionEvent extends RecognitionEvent implements Parcelable {
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001450 @UnsupportedAppUsage
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001451 public GenericRecognitionEvent(int status, int soundModelHandle,
1452 boolean captureAvailable, int captureSession, int captureDelayMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001453 int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat,
1454 @Nullable byte[] data) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001455 super(status, soundModelHandle, captureAvailable, captureSession,
1456 captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
1457 data);
1458 }
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001459
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001460 public static final @android.annotation.NonNull Parcelable.Creator<GenericRecognitionEvent> CREATOR
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001461 = new Parcelable.Creator<GenericRecognitionEvent>() {
1462 public GenericRecognitionEvent createFromParcel(Parcel in) {
1463 return GenericRecognitionEvent.fromParcelForGeneric(in);
1464 }
1465
1466 public GenericRecognitionEvent[] newArray(int size) {
1467 return new GenericRecognitionEvent[size];
1468 }
1469 };
1470
1471 private static GenericRecognitionEvent fromParcelForGeneric(Parcel in) {
1472 RecognitionEvent event = RecognitionEvent.fromParcel(in);
1473 return new GenericRecognitionEvent(event.status, event.soundModelHandle,
1474 event.captureAvailable, event.captureSession, event.captureDelayMs,
1475 event.capturePreambleMs, event.triggerInData, event.captureFormat, event.data);
1476 }
1477
1478 @Override
1479 public boolean equals(Object obj) {
1480 if (this == obj)
1481 return true;
1482 if (obj == null)
1483 return false;
1484 if (getClass() != obj.getClass()) return false;
1485 RecognitionEvent other = (RecognitionEvent) obj;
1486 return super.equals(obj);
1487 }
1488
1489 @Override
1490 public String toString() {
1491 return "GenericRecognitionEvent ::" + super.toString();
1492 }
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001493 }
1494
1495 /**
Eric Laurentd3b82232014-07-30 08:57:39 -07001496 * Status codes for {@link SoundModelEvent}
1497 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001498 /**
1499 * Sound Model was updated
1500 *
1501 * @hide
1502 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001503 public static final int SOUNDMODEL_STATUS_UPDATED = 0;
1504
1505 /**
1506 * A SoundModelEvent is provided by the
1507 * {@link StatusListener#onSoundModelUpdate(SoundModelEvent)}
1508 * callback when a sound model has been updated by the implementation
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001509 *
1510 * @hide
Eric Laurentd3b82232014-07-30 08:57:39 -07001511 */
1512 public static class SoundModelEvent implements Parcelable {
1513 /** Status e.g {@link #SOUNDMODEL_STATUS_UPDATED} */
1514 public final int status;
1515 /** The updated sound model handle */
1516 public final int soundModelHandle;
1517 /** New sound model data */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001518 @NonNull
Eric Laurentd3b82232014-07-30 08:57:39 -07001519 public final byte[] data;
1520
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001521 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001522 SoundModelEvent(int status, int soundModelHandle, @Nullable byte[] data) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001523 this.status = status;
1524 this.soundModelHandle = soundModelHandle;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001525 this.data = data != null ? data : new byte[0];
Eric Laurentd3b82232014-07-30 08:57:39 -07001526 }
1527
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001528 public static final @android.annotation.NonNull Parcelable.Creator<SoundModelEvent> CREATOR
Eric Laurentd3b82232014-07-30 08:57:39 -07001529 = new Parcelable.Creator<SoundModelEvent>() {
1530 public SoundModelEvent createFromParcel(Parcel in) {
1531 return SoundModelEvent.fromParcel(in);
1532 }
1533
1534 public SoundModelEvent[] newArray(int size) {
1535 return new SoundModelEvent[size];
1536 }
1537 };
1538
1539 private static SoundModelEvent fromParcel(Parcel in) {
1540 int status = in.readInt();
1541 int soundModelHandle = in.readInt();
1542 byte[] data = in.readBlob();
1543 return new SoundModelEvent(status, soundModelHandle, data);
1544 }
1545
1546 @Override
1547 public int describeContents() {
1548 return 0;
1549 }
1550
1551 @Override
1552 public void writeToParcel(Parcel dest, int flags) {
1553 dest.writeInt(status);
1554 dest.writeInt(soundModelHandle);
1555 dest.writeBlob(data);
1556 }
1557
1558 @Override
1559 public int hashCode() {
1560 final int prime = 31;
1561 int result = 1;
1562 result = prime * result + Arrays.hashCode(data);
1563 result = prime * result + soundModelHandle;
1564 result = prime * result + status;
1565 return result;
1566 }
1567
1568 @Override
1569 public boolean equals(Object obj) {
1570 if (this == obj)
1571 return true;
1572 if (obj == null)
1573 return false;
1574 if (getClass() != obj.getClass())
1575 return false;
1576 SoundModelEvent other = (SoundModelEvent) obj;
1577 if (!Arrays.equals(data, other.data))
1578 return false;
1579 if (soundModelHandle != other.soundModelHandle)
1580 return false;
1581 if (status != other.status)
1582 return false;
1583 return true;
1584 }
1585
1586 @Override
1587 public String toString() {
1588 return "SoundModelEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
1589 + ", data=" + (data == null ? 0 : data.length) + "]";
1590 }
1591 }
1592
1593 /**
1594 * Native service state. {@link StatusListener#onServiceStateChange(int)}
1595 */
1596 // Keep in sync with system/core/include/system/sound_trigger.h
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001597 /**
1598 * Sound trigger service is enabled
1599 *
1600 * @hide
1601 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001602 public static final int SERVICE_STATE_ENABLED = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001603 /**
1604 * Sound trigger service is disabled
1605 *
1606 * @hide
1607 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001608 public static final int SERVICE_STATE_DISABLED = 1;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001609 private static Object mServiceLock = new Object();
1610 private static ISoundTriggerMiddlewareService mService;
1611 /**
jiabin1f4b4dd2019-03-18 18:07:03 -07001612 * @return returns current package name.
1613 */
1614 static String getCurrentOpPackageName() {
1615 String packageName = ActivityThread.currentOpPackageName();
1616 if (packageName == null) {
1617 return "";
1618 }
1619 return packageName;
1620 }
1621
1622 /**
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001623 * Returns a list of descriptors for all hardware modules loaded.
Eric Laurente48188c2014-04-18 17:44:11 -07001624 * @param modules A ModuleProperties array where the list will be returned.
1625 * @return - {@link #STATUS_OK} in case of success
1626 * - {@link #STATUS_ERROR} in case of unspecified error
1627 * - {@link #STATUS_PERMISSION_DENIED} if the caller does not have system permission
1628 * - {@link #STATUS_NO_INIT} if the native service cannot be reached
1629 * - {@link #STATUS_BAD_VALUE} if modules is null
1630 * - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001631 *
1632 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001633 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001634 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001635 public static int listModules(@NonNull ArrayList<ModuleProperties> modules) {
1636 try {
1637 SoundTriggerModuleDescriptor[] descs = getService().listModules();
1638 modules.clear();
1639 modules.ensureCapacity(descs.length);
1640 for (SoundTriggerModuleDescriptor desc : descs) {
1641 modules.add(ConversionUtil.aidl2apiModuleDescriptor(desc));
1642 }
1643 return STATUS_OK;
1644 } catch (RemoteException e) {
1645 Log.e(TAG, "Exception caught", e);
1646 return STATUS_DEAD_OBJECT;
1647 }
jiabin1f4b4dd2019-03-18 18:07:03 -07001648 }
1649
1650 /**
Eric Laurente48188c2014-04-18 17:44:11 -07001651 * Get an interface on a hardware module to control sound models and recognition on
1652 * this module.
1653 * @param moduleId Sound module system identifier {@link ModuleProperties#id}. mandatory.
1654 * @param listener {@link StatusListener} interface. Mandatory.
1655 * @param handler the Handler that will receive the callabcks. Can be null if default handler
1656 * is OK.
1657 * @return a valid sound module in case of success or null in case of error.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001658 *
1659 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001660 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001661 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001662 public static @NonNull SoundTriggerModule attachModule(int moduleId,
1663 @NonNull StatusListener listener,
1664 @Nullable Handler handler) {
1665 Looper looper = handler != null ? handler.getLooper() : Looper.getMainLooper();
1666 try {
1667 return new SoundTriggerModule(getService(), moduleId, listener, looper);
1668 } catch (RemoteException e) {
1669 Log.e(TAG, "", e);
Eric Laurente48188c2014-04-18 17:44:11 -07001670 return null;
1671 }
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001672 }
1673
1674 private static ISoundTriggerMiddlewareService getService() {
1675 synchronized (mServiceLock) {
1676 while (true) {
1677 IBinder binder = null;
1678 try {
1679 binder =
1680 ServiceManager.getServiceOrThrow(
1681 Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE);
1682 binder.linkToDeath(() -> {
1683 synchronized (mServiceLock) {
1684 mService = null;
1685 }
1686 }, 0);
1687 mService = ISoundTriggerMiddlewareService.Stub.asInterface(binder);
1688 break;
1689 } catch (Exception e) {
1690 Log.e(TAG, "Failed to bind to soundtrigger service", e);
1691 }
1692 }
1693 return mService;
1694 }
1695
Eric Laurente48188c2014-04-18 17:44:11 -07001696 }
1697
1698 /**
1699 * Interface provided by the client application when attaching to a {@link SoundTriggerModule}
1700 * to received recognition and error notifications.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001701 *
1702 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001703 */
1704 public static interface StatusListener {
1705 /**
1706 * Called when recognition succeeds of fails
1707 */
1708 public abstract void onRecognition(RecognitionEvent event);
1709
1710 /**
Eric Laurentd3b82232014-07-30 08:57:39 -07001711 * Called when a sound model has been updated
1712 */
1713 public abstract void onSoundModelUpdate(SoundModelEvent event);
1714
1715 /**
1716 * Called when the sound trigger native service state changes.
1717 * @param state Native service state. One of {@link SoundTrigger#SERVICE_STATE_ENABLED},
1718 * {@link SoundTrigger#SERVICE_STATE_DISABLED}
1719 */
1720 public abstract void onServiceStateChange(int state);
1721
1722 /**
Eric Laurente48188c2014-04-18 17:44:11 -07001723 * Called when the sound trigger native service dies
1724 */
1725 public abstract void onServiceDied();
1726 }
1727}