1 /* 2 * Copyright (C) 2021 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 com.android.server.soundtrigger_middleware; 18 19 import android.annotation.NonNull; 20 import android.hardware.soundtrigger3.ISoundTriggerHw; 21 import android.hardware.soundtrigger3.ISoundTriggerHwCallback; 22 import android.hardware.soundtrigger3.ISoundTriggerHwGlobalCallback; 23 import android.media.soundtrigger.ModelParameterRange; 24 import android.media.soundtrigger.PhraseRecognitionEvent; 25 import android.media.soundtrigger.PhraseSoundModel; 26 import android.media.soundtrigger.Properties; 27 import android.media.soundtrigger.RecognitionConfig; 28 import android.media.soundtrigger.RecognitionEvent; 29 import android.media.soundtrigger.RecognitionStatus; 30 import android.media.soundtrigger.SoundModel; 31 import android.media.soundtrigger.Status; 32 import android.media.soundtrigger_middleware.PhraseRecognitionEventSys; 33 import android.media.soundtrigger_middleware.RecognitionEventSys; 34 import android.os.IBinder; 35 import android.os.RemoteException; 36 import android.os.ServiceSpecificException; 37 import android.os.SystemClock; 38 39 public class SoundTriggerHw3Compat implements ISoundTriggerHal { 40 private final @NonNull ISoundTriggerHw mDriver; 41 private final @NonNull Runnable mRebootRunnable; 42 SoundTriggerHw3Compat(@onNull IBinder binder, @NonNull Runnable rebootRunnable)43 public SoundTriggerHw3Compat(@NonNull IBinder binder, @NonNull Runnable rebootRunnable) { 44 mDriver = android.hardware.soundtrigger3.ISoundTriggerHw.Stub.asInterface(binder); 45 mRebootRunnable = rebootRunnable; 46 } 47 48 @Override getProperties()49 public Properties getProperties() { 50 try { 51 return mDriver.getProperties(); 52 } catch (RemoteException e) { 53 throw e.rethrowAsRuntimeException(); 54 } 55 } 56 57 @Override registerCallback(GlobalCallback callback)58 public void registerCallback(GlobalCallback callback) { 59 try { 60 mDriver.registerGlobalCallback(new GlobalCallbackAdaper(callback)); 61 } catch (RemoteException e) { 62 throw e.rethrowAsRuntimeException(); 63 } 64 } 65 66 @Override loadSoundModel(SoundModel soundModel, ModelCallback callback)67 public int loadSoundModel(SoundModel soundModel, ModelCallback callback) { 68 try { 69 return mDriver.loadSoundModel(soundModel, new ModelCallbackAdaper(callback)); 70 } catch (RemoteException e) { 71 throw e.rethrowAsRuntimeException(); 72 } catch (ServiceSpecificException e) { 73 if (e.errorCode == Status.RESOURCE_CONTENTION) { 74 throw new RecoverableException(Status.RESOURCE_CONTENTION); 75 } 76 throw e; 77 } 78 } 79 80 @Override loadPhraseSoundModel(PhraseSoundModel soundModel, ModelCallback callback)81 public int loadPhraseSoundModel(PhraseSoundModel soundModel, ModelCallback callback) { 82 try { 83 return mDriver.loadPhraseSoundModel(soundModel, new ModelCallbackAdaper(callback)); 84 } catch (RemoteException e) { 85 throw e.rethrowAsRuntimeException(); 86 } catch (ServiceSpecificException e) { 87 if (e.errorCode == Status.RESOURCE_CONTENTION) { 88 throw new RecoverableException(Status.RESOURCE_CONTENTION); 89 } 90 throw e; 91 } 92 } 93 94 @Override unloadSoundModel(int modelHandle)95 public void unloadSoundModel(int modelHandle) { 96 try { 97 mDriver.unloadSoundModel(modelHandle); 98 } catch (RemoteException e) { 99 throw e.rethrowAsRuntimeException(); 100 } 101 } 102 103 @Override startRecognition(int modelHandle, int deviceHandle, int ioHandle, RecognitionConfig config)104 public void startRecognition(int modelHandle, int deviceHandle, int ioHandle, 105 RecognitionConfig config) { 106 try { 107 mDriver.startRecognition(modelHandle, deviceHandle, ioHandle, config); 108 } catch (RemoteException e) { 109 throw e.rethrowAsRuntimeException(); 110 } catch (ServiceSpecificException e) { 111 if (e.errorCode == Status.RESOURCE_CONTENTION) { 112 throw new RecoverableException(Status.RESOURCE_CONTENTION); 113 } 114 throw e; 115 } 116 } 117 118 @Override stopRecognition(int modelHandle)119 public void stopRecognition(int modelHandle) { 120 try { 121 mDriver.stopRecognition(modelHandle); 122 } catch (RemoteException e) { 123 throw e.rethrowAsRuntimeException(); 124 } 125 } 126 127 @Override forceRecognitionEvent(int modelHandle)128 public void forceRecognitionEvent(int modelHandle) { 129 try { 130 mDriver.forceRecognitionEvent(modelHandle); 131 } catch (RemoteException e) { 132 throw e.rethrowAsRuntimeException(); 133 } 134 } 135 136 @Override queryParameter(int modelHandle, int param)137 public ModelParameterRange queryParameter(int modelHandle, int param) { 138 try { 139 return mDriver.queryParameter(modelHandle, param); 140 } catch (RemoteException e) { 141 throw e.rethrowAsRuntimeException(); 142 } 143 } 144 145 @Override getModelParameter(int modelHandle, int param)146 public int getModelParameter(int modelHandle, int param) { 147 try { 148 return mDriver.getParameter(modelHandle, param); 149 } catch (RemoteException e) { 150 throw e.rethrowAsRuntimeException(); 151 } 152 } 153 154 @Override setModelParameter(int modelHandle, int param, int value)155 public void setModelParameter(int modelHandle, int param, int value) { 156 try { 157 mDriver.setParameter(modelHandle, param, value); 158 } catch (RemoteException e) { 159 throw e.rethrowAsRuntimeException(); 160 } 161 } 162 163 @Override interfaceDescriptor()164 public String interfaceDescriptor() { 165 try { 166 return mDriver.asBinder().getInterfaceDescriptor(); 167 } catch (RemoteException e) { 168 throw e.rethrowAsRuntimeException(); 169 } 170 } 171 172 @Override linkToDeath(IBinder.DeathRecipient recipient)173 public void linkToDeath(IBinder.DeathRecipient recipient) { 174 try { 175 mDriver.asBinder().linkToDeath(recipient, 0); 176 } catch (RemoteException e) { 177 throw e.rethrowAsRuntimeException(); 178 } 179 } 180 181 @Override unlinkToDeath(IBinder.DeathRecipient recipient)182 public void unlinkToDeath(IBinder.DeathRecipient recipient) { 183 mDriver.asBinder().unlinkToDeath(recipient, 0); 184 } 185 186 @Override flushCallbacks()187 public void flushCallbacks() { 188 // No-op. 189 } 190 191 @Override clientAttached(IBinder binder)192 public void clientAttached(IBinder binder) { 193 // No-op. This method is for test purposes, and is intercepted above. 194 } 195 196 @Override clientDetached(IBinder binder)197 public void clientDetached(IBinder binder) { 198 // No-op. This method is for test purposes, and is intercepted above. 199 } 200 201 @Override reboot()202 public void reboot() { 203 mRebootRunnable.run(); 204 } 205 206 @Override detach()207 public void detach() { 208 // No-op. 209 } 210 211 private static class GlobalCallbackAdaper extends ISoundTriggerHwGlobalCallback.Stub { 212 private final @NonNull GlobalCallback mDelegate; 213 GlobalCallbackAdaper(@onNull GlobalCallback callback)214 public GlobalCallbackAdaper(@NonNull GlobalCallback callback) { 215 mDelegate = callback; 216 } 217 218 @Override onResourcesAvailable()219 public void onResourcesAvailable() { 220 mDelegate.onResourcesAvailable(); 221 } 222 223 @Override getInterfaceVersion()224 public int getInterfaceVersion() { 225 return ISoundTriggerHwGlobalCallback.VERSION; 226 } 227 228 @Override getInterfaceHash()229 public String getInterfaceHash() { 230 return ISoundTriggerHwGlobalCallback.HASH; 231 } 232 } 233 234 private static class ModelCallbackAdaper extends ISoundTriggerHwCallback.Stub { 235 private final @NonNull ModelCallback mDelegate; 236 ModelCallbackAdaper(ModelCallback callback)237 public ModelCallbackAdaper(ModelCallback callback) { 238 mDelegate = callback; 239 } 240 241 @Override modelUnloaded(int model)242 public void modelUnloaded(int model) { 243 mDelegate.modelUnloaded(model); 244 } 245 246 @Override phraseRecognitionCallback(int model, PhraseRecognitionEvent event)247 public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) { 248 // A FORCED status implies that recognition is still active after the event. 249 event.common.recognitionStillActive |= event.common.status == RecognitionStatus.FORCED; 250 PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys(); 251 phraseRecognitionEventSys.phraseRecognitionEvent = event; 252 phraseRecognitionEventSys.halEventReceivedMillis = SystemClock.elapsedRealtimeNanos(); 253 mDelegate.phraseRecognitionCallback(model, phraseRecognitionEventSys); 254 } 255 256 @Override recognitionCallback(int model, RecognitionEvent event)257 public void recognitionCallback(int model, RecognitionEvent event) { 258 // A FORCED status implies that recognition is still active after the event. 259 event.recognitionStillActive |= event.status == RecognitionStatus.FORCED; 260 RecognitionEventSys recognitionEventSys = new RecognitionEventSys(); 261 recognitionEventSys.recognitionEvent = event; 262 recognitionEventSys.halEventReceivedMillis = SystemClock.elapsedRealtimeNanos(); 263 mDelegate.recognitionCallback(model, recognitionEventSys); 264 } 265 266 @Override getInterfaceVersion()267 public int getInterfaceVersion() { 268 return ISoundTriggerHwCallback.VERSION; 269 } 270 271 @Override getInterfaceHash()272 public String getInterfaceHash() { 273 return ISoundTriggerHwCallback.HASH; 274 } 275 } 276 } 277