1 /* 2 * Copyright (C) 2019 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.media.soundtrigger_middleware.ISoundTriggerCallback; 21 import android.media.soundtrigger_middleware.ISoundTriggerModule; 22 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; 23 import android.util.Slog; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** 29 * This is an implementation of the ISoundTriggerMiddlewareService interface. 30 * <p> 31 * <b>Important conventions:</b> 32 * <ul> 33 * <li>Correct usage is assumed. This implementation does not attempt to gracefully handle invalid 34 * usage, and such usage will result in undefined behavior. If this service is to be offered to an 35 * untrusted client, it must be wrapped with input and state validation. 36 * <li>There is no binder instance associated with this implementation. Do not call asBinder(). 37 * <li>The implementation may throw a {@link RecoverableException} to indicate non-fatal, 38 * recoverable faults. The error code would one of the 39 * {@link android.media.soundtrigger.Status} 40 * constants. Any other exception thrown should be regarded as a bug in the implementation or one 41 * of its dependencies (assuming correct usage). 42 * <li>The implementation is designed for testibility by featuring dependency injection (the 43 * underlying HAL driver instances are passed to the ctor) and by minimizing dependencies on 44 * Android runtime. 45 * <li>The implementation is thread-safe. 46 * </ul> 47 * 48 * @hide 49 */ 50 public class SoundTriggerMiddlewareImpl implements ISoundTriggerMiddlewareInternal { 51 static private final String TAG = "SoundTriggerMiddlewareImpl"; 52 private final SoundTriggerModule[] mModules; 53 54 /** 55 * Interface to the audio system, which can allocate capture session handles. 56 * SoundTrigger uses those sessions in order to associate a recognition session with an optional 57 * capture from the same device that triggered the recognition. 58 */ 59 public static abstract class AudioSessionProvider { 60 public static final class AudioSession { 61 final int mSessionHandle; 62 final int mIoHandle; 63 final int mDeviceHandle; 64 AudioSession(int sessionHandle, int ioHandle, int deviceHandle)65 AudioSession(int sessionHandle, int ioHandle, int deviceHandle) { 66 mSessionHandle = sessionHandle; 67 mIoHandle = ioHandle; 68 mDeviceHandle = deviceHandle; 69 } 70 } 71 acquireSession()72 public abstract AudioSession acquireSession(); 73 releaseSession(int sessionHandle)74 public abstract void releaseSession(int sessionHandle); 75 } 76 77 /** 78 * Constructor - gets an array of HAL driver factories. 79 */ SoundTriggerMiddlewareImpl(@onNull HalFactory[] halFactories, @NonNull AudioSessionProvider audioSessionProvider)80 public SoundTriggerMiddlewareImpl(@NonNull HalFactory[] halFactories, 81 @NonNull AudioSessionProvider audioSessionProvider) { 82 List<SoundTriggerModule> modules = new ArrayList<>(halFactories.length); 83 84 for (HalFactory halFactory : halFactories) { 85 try { 86 modules.add(new SoundTriggerModule(halFactory, audioSessionProvider)); 87 } catch (Exception e) { 88 Slog.e(TAG, "Failed to add a SoundTriggerModule instance", e); 89 } 90 } 91 92 mModules = modules.toArray(new SoundTriggerModule[0]); 93 } 94 95 /** 96 * Convenience constructor - gets a single HAL factory. 97 */ SoundTriggerMiddlewareImpl(@onNull HalFactory factory, @NonNull AudioSessionProvider audioSessionProvider)98 public SoundTriggerMiddlewareImpl(@NonNull HalFactory factory, 99 @NonNull AudioSessionProvider audioSessionProvider) { 100 this(new HalFactory[]{factory}, audioSessionProvider); 101 } 102 103 @Override 104 public @NonNull listModules()105 SoundTriggerModuleDescriptor[] listModules() { 106 SoundTriggerModuleDescriptor[] result = new SoundTriggerModuleDescriptor[mModules.length]; 107 108 for (int i = 0; i < mModules.length; ++i) { 109 SoundTriggerModuleDescriptor desc = new SoundTriggerModuleDescriptor(); 110 desc.handle = i; 111 desc.properties = mModules[i].getProperties(); 112 result[i] = desc; 113 } 114 return result; 115 } 116 117 @Override 118 public @NonNull attach(int handle, @NonNull ISoundTriggerCallback callback, boolean isTrusted)119 ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback, 120 boolean isTrusted) { 121 return mModules[handle].attach(callback); 122 } 123 } 124