1 /* 2 * 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 17 package android.hardware.soundtrigger; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.os.Handler; 21 import android.os.Looper; 22 import android.os.Message; 23 24 import java.lang.ref.WeakReference; 25 26 /** 27 * The SoundTriggerModule provides APIs to control sound models and sound detection 28 * on a given sound trigger hardware module. 29 * 30 * @hide 31 */ 32 public class SoundTriggerModule { 33 @UnsupportedAppUsage 34 private long mNativeContext; 35 36 @UnsupportedAppUsage 37 private int mId; 38 private NativeEventHandlerDelegate mEventHandlerDelegate; 39 40 // to be kept in sync with core/jni/android_hardware_SoundTrigger.cpp 41 private static final int EVENT_RECOGNITION = 1; 42 private static final int EVENT_SERVICE_DIED = 2; 43 private static final int EVENT_SOUNDMODEL = 3; 44 private static final int EVENT_SERVICE_STATE_CHANGE = 4; 45 SoundTriggerModule(int moduleId, SoundTrigger.StatusListener listener, Handler handler)46 SoundTriggerModule(int moduleId, SoundTrigger.StatusListener listener, Handler handler) { 47 mId = moduleId; 48 mEventHandlerDelegate = new NativeEventHandlerDelegate(listener, handler); 49 native_setup(SoundTrigger.getCurrentOpPackageName(), 50 new WeakReference<SoundTriggerModule>(this)); 51 } native_setup(String opPackageName, Object moduleThis)52 private native void native_setup(String opPackageName, Object moduleThis); 53 54 @Override finalize()55 protected void finalize() { 56 native_finalize(); 57 } native_finalize()58 private native void native_finalize(); 59 60 /** 61 * Detach from this module. The {@link SoundTrigger.StatusListener} callback will not be called 62 * anymore and associated resources will be released. 63 * */ 64 @UnsupportedAppUsage detach()65 public native void detach(); 66 67 /** 68 * Load a {@link SoundTrigger.SoundModel} to the hardware. A sound model must be loaded in 69 * order to start listening to a key phrase in this model. 70 * @param model The sound model to load. 71 * @param soundModelHandle an array of int where the sound model handle will be returned. 72 * @return - {@link SoundTrigger#STATUS_OK} in case of success 73 * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error 74 * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have 75 * system permission 76 * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached 77 * - {@link SoundTrigger#STATUS_BAD_VALUE} if parameters are invalid 78 * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native 79 * service fails 80 * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence 81 */ 82 @UnsupportedAppUsage loadSoundModel(SoundTrigger.SoundModel model, int[] soundModelHandle)83 public native int loadSoundModel(SoundTrigger.SoundModel model, int[] soundModelHandle); 84 85 /** 86 * Unload a {@link SoundTrigger.SoundModel} and abort any pendiong recognition 87 * @param soundModelHandle The sound model handle 88 * @return - {@link SoundTrigger#STATUS_OK} in case of success 89 * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error 90 * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have 91 * system permission 92 * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached 93 * - {@link SoundTrigger#STATUS_BAD_VALUE} if the sound model handle is invalid 94 * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native 95 * service fails 96 */ 97 @UnsupportedAppUsage unloadSoundModel(int soundModelHandle)98 public native int unloadSoundModel(int soundModelHandle); 99 100 /** 101 * Start listening to all key phrases in a {@link SoundTrigger.SoundModel}. 102 * Recognition must be restarted after each callback (success or failure) received on 103 * the {@link SoundTrigger.StatusListener}. 104 * @param soundModelHandle The sound model handle to start listening to 105 * @param config contains configuration information for this recognition request: 106 * recognition mode, keyphrases, users, minimum confidence levels... 107 * @return - {@link SoundTrigger#STATUS_OK} in case of success 108 * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error 109 * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have 110 * system permission 111 * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached 112 * - {@link SoundTrigger#STATUS_BAD_VALUE} if the sound model handle is invalid 113 * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native 114 * service fails 115 * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence 116 */ 117 @UnsupportedAppUsage startRecognition(int soundModelHandle, SoundTrigger.RecognitionConfig config)118 public native int startRecognition(int soundModelHandle, SoundTrigger.RecognitionConfig config); 119 120 /** 121 * Stop listening to all key phrases in a {@link SoundTrigger.SoundModel} 122 * @param soundModelHandle The sound model handle to stop listening to 123 * @return - {@link SoundTrigger#STATUS_OK} in case of success 124 * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error 125 * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have 126 * system permission 127 * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached 128 * - {@link SoundTrigger#STATUS_BAD_VALUE} if the sound model handle is invalid 129 * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native 130 * service fails 131 * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence 132 */ 133 @UnsupportedAppUsage stopRecognition(int soundModelHandle)134 public native int stopRecognition(int soundModelHandle); 135 136 /** 137 * Get the current state of a {@link SoundTrigger.SoundModel}. 138 * The state will be returned asynchronously as a {@link SoundTrigger#RecognitionEvent} 139 * in the callback registered in the {@link SoundTrigger.startRecognition} method. 140 * @param soundModelHandle The sound model handle indicating which model's state to return 141 * @return - {@link SoundTrigger#STATUS_OK} in case of success 142 * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error 143 * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have 144 * system permission 145 * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached 146 * - {@link SoundTrigger#STATUS_BAD_VALUE} if the sound model handle is invalid 147 * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native 148 * service fails 149 * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence 150 */ getModelState(int soundModelHandle)151 public native int getModelState(int soundModelHandle); 152 153 private class NativeEventHandlerDelegate { 154 private final Handler mHandler; 155 NativeEventHandlerDelegate(final SoundTrigger.StatusListener listener, Handler handler)156 NativeEventHandlerDelegate(final SoundTrigger.StatusListener listener, 157 Handler handler) { 158 // find the looper for our new event handler 159 Looper looper; 160 if (handler != null) { 161 looper = handler.getLooper(); 162 } else { 163 looper = Looper.getMainLooper(); 164 } 165 166 // construct the event handler with this looper 167 if (looper != null) { 168 // implement the event handler delegate 169 mHandler = new Handler(looper) { 170 @Override 171 public void handleMessage(Message msg) { 172 switch(msg.what) { 173 case EVENT_RECOGNITION: 174 if (listener != null) { 175 listener.onRecognition( 176 (SoundTrigger.RecognitionEvent)msg.obj); 177 } 178 break; 179 case EVENT_SOUNDMODEL: 180 if (listener != null) { 181 listener.onSoundModelUpdate( 182 (SoundTrigger.SoundModelEvent)msg.obj); 183 } 184 break; 185 case EVENT_SERVICE_STATE_CHANGE: 186 if (listener != null) { 187 listener.onServiceStateChange(msg.arg1); 188 } 189 break; 190 case EVENT_SERVICE_DIED: 191 if (listener != null) { 192 listener.onServiceDied(); 193 } 194 break; 195 default: 196 break; 197 } 198 } 199 }; 200 } else { 201 mHandler = null; 202 } 203 } 204 handler()205 Handler handler() { 206 return mHandler; 207 } 208 } 209 210 @SuppressWarnings("unused") 211 @UnsupportedAppUsage postEventFromNative(Object module_ref, int what, int arg1, int arg2, Object obj)212 private static void postEventFromNative(Object module_ref, 213 int what, int arg1, int arg2, Object obj) { 214 SoundTriggerModule module = (SoundTriggerModule)((WeakReference)module_ref).get(); 215 if (module == null) { 216 return; 217 } 218 219 NativeEventHandlerDelegate delegate = module.mEventHandlerDelegate; 220 if (delegate != null) { 221 Handler handler = delegate.handler(); 222 if (handler != null) { 223 Message m = handler.obtainMessage(what, arg1, arg2, obj); 224 handler.sendMessage(m); 225 } 226 } 227 } 228 } 229