• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.hardware.soundtrigger;
18 
19 import android.annotation.Nullable;
20 import android.media.AudioFormat;
21 import android.media.audio.common.AidlConversion;
22 import android.media.audio.common.AudioConfig;
23 import android.media.soundtrigger.AudioCapabilities;
24 import android.media.soundtrigger.ConfidenceLevel;
25 import android.media.soundtrigger.ModelParameterRange;
26 import android.media.soundtrigger.Phrase;
27 import android.media.soundtrigger.PhraseRecognitionEvent;
28 import android.media.soundtrigger.PhraseRecognitionExtra;
29 import android.media.soundtrigger.PhraseSoundModel;
30 import android.media.soundtrigger.Properties;
31 import android.media.soundtrigger.RecognitionConfig;
32 import android.media.soundtrigger.RecognitionEvent;
33 import android.media.soundtrigger.RecognitionMode;
34 import android.media.soundtrigger.SoundModel;
35 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
36 import android.os.ParcelFileDescriptor;
37 import android.os.SharedMemory;
38 
39 import java.nio.ByteBuffer;
40 import java.util.Arrays;
41 import java.util.UUID;
42 
43 /** @hide */
44 class ConversionUtil {
aidl2apiModuleDescriptor( SoundTriggerModuleDescriptor aidlDesc)45     public static SoundTrigger.ModuleProperties aidl2apiModuleDescriptor(
46             SoundTriggerModuleDescriptor aidlDesc) {
47         Properties properties = aidlDesc.properties;
48         return new SoundTrigger.ModuleProperties(
49                 aidlDesc.handle,
50                 properties.implementor,
51                 properties.description,
52                 properties.uuid,
53                 properties.version,
54                 properties.supportedModelArch,
55                 properties.maxSoundModels,
56                 properties.maxKeyPhrases,
57                 properties.maxUsers,
58                 aidl2apiRecognitionModes(properties.recognitionModes),
59                 properties.captureTransition,
60                 properties.maxBufferMs,
61                 properties.concurrentCapture,
62                 properties.powerConsumptionMw,
63                 properties.triggerInEvent,
64                 aidl2apiAudioCapabilities(properties.audioCapabilities)
65         );
66     }
67 
aidl2apiRecognitionModes(int aidlModes)68     public static int aidl2apiRecognitionModes(int aidlModes) {
69         int result = 0;
70         if ((aidlModes & RecognitionMode.VOICE_TRIGGER) != 0) {
71             result |= SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER;
72         }
73         if ((aidlModes & RecognitionMode.USER_IDENTIFICATION) != 0) {
74             result |= SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
75         }
76         if ((aidlModes & RecognitionMode.USER_AUTHENTICATION) != 0) {
77             result |= SoundTrigger.RECOGNITION_MODE_USER_AUTHENTICATION;
78         }
79         if ((aidlModes & RecognitionMode.GENERIC_TRIGGER) != 0) {
80             result |= SoundTrigger.RECOGNITION_MODE_GENERIC;
81         }
82         return result;
83     }
84 
api2aidlRecognitionModes(int apiModes)85     public static int api2aidlRecognitionModes(int apiModes) {
86         int result = 0;
87         if ((apiModes & SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER) != 0) {
88             result |= RecognitionMode.VOICE_TRIGGER;
89         }
90         if ((apiModes & SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION) != 0) {
91             result |= RecognitionMode.USER_IDENTIFICATION;
92         }
93         if ((apiModes & SoundTrigger.RECOGNITION_MODE_USER_AUTHENTICATION) != 0) {
94             result |= RecognitionMode.USER_AUTHENTICATION;
95         }
96         if ((apiModes & SoundTrigger.RECOGNITION_MODE_GENERIC) != 0) {
97             result |= RecognitionMode.GENERIC_TRIGGER;
98         }
99         return result;
100     }
101 
102 
api2aidlGenericSoundModel(SoundTrigger.GenericSoundModel apiModel)103     public static SoundModel api2aidlGenericSoundModel(SoundTrigger.GenericSoundModel apiModel) {
104         return api2aidlSoundModel(apiModel);
105     }
106 
api2aidlSoundModel(SoundTrigger.SoundModel apiModel)107     public static SoundModel api2aidlSoundModel(SoundTrigger.SoundModel apiModel) {
108         SoundModel aidlModel = new SoundModel();
109         aidlModel.type = apiModel.getType();
110         aidlModel.uuid = api2aidlUuid(apiModel.getUuid());
111         aidlModel.vendorUuid = api2aidlUuid(apiModel.getVendorUuid());
112         byte[] data = apiModel.getData();
113         aidlModel.data = byteArrayToSharedMemory(data, "SoundTrigger SoundModel");
114         aidlModel.dataSize = data.length;
115         return aidlModel;
116     }
117 
api2aidlUuid(UUID apiUuid)118     public static String api2aidlUuid(UUID apiUuid) {
119         return apiUuid.toString();
120     }
121 
api2aidlPhraseSoundModel( SoundTrigger.KeyphraseSoundModel apiModel)122     public static PhraseSoundModel api2aidlPhraseSoundModel(
123             SoundTrigger.KeyphraseSoundModel apiModel) {
124         PhraseSoundModel aidlModel = new PhraseSoundModel();
125         aidlModel.common = api2aidlSoundModel(apiModel);
126         aidlModel.phrases = new Phrase[apiModel.getKeyphrases().length];
127         for (int i = 0; i < apiModel.getKeyphrases().length; ++i) {
128             aidlModel.phrases[i] = api2aidlPhrase(apiModel.getKeyphrases()[i]);
129         }
130         return aidlModel;
131     }
132 
api2aidlPhrase(SoundTrigger.Keyphrase apiPhrase)133     public static Phrase api2aidlPhrase(SoundTrigger.Keyphrase apiPhrase) {
134         Phrase aidlPhrase = new Phrase();
135         aidlPhrase.id = apiPhrase.getId();
136         aidlPhrase.recognitionModes = api2aidlRecognitionModes(apiPhrase.getRecognitionModes());
137         aidlPhrase.users = Arrays.copyOf(apiPhrase.getUsers(), apiPhrase.getUsers().length);
138         aidlPhrase.locale = apiPhrase.getLocale().toLanguageTag();
139         aidlPhrase.text = apiPhrase.getText();
140         return aidlPhrase;
141     }
142 
api2aidlRecognitionConfig( SoundTrigger.RecognitionConfig apiConfig)143     public static RecognitionConfig api2aidlRecognitionConfig(
144             SoundTrigger.RecognitionConfig apiConfig) {
145         RecognitionConfig aidlConfig = new RecognitionConfig();
146         aidlConfig.captureRequested = apiConfig.captureRequested;
147         // apiConfig.allowMultipleTriggers is ignored by the lower layers.
148         aidlConfig.phraseRecognitionExtras =
149                 new PhraseRecognitionExtra[apiConfig.keyphrases.length];
150         for (int i = 0; i < apiConfig.keyphrases.length; ++i) {
151             aidlConfig.phraseRecognitionExtras[i] = api2aidlPhraseRecognitionExtra(
152                     apiConfig.keyphrases[i]);
153         }
154         aidlConfig.data = Arrays.copyOf(apiConfig.data, apiConfig.data.length);
155         aidlConfig.audioCapabilities = api2aidlAudioCapabilities(apiConfig.audioCapabilities);
156         return aidlConfig;
157     }
158 
api2aidlPhraseRecognitionExtra( SoundTrigger.KeyphraseRecognitionExtra apiExtra)159     public static PhraseRecognitionExtra api2aidlPhraseRecognitionExtra(
160             SoundTrigger.KeyphraseRecognitionExtra apiExtra) {
161         PhraseRecognitionExtra aidlExtra = new PhraseRecognitionExtra();
162         aidlExtra.id = apiExtra.id;
163         aidlExtra.recognitionModes = api2aidlRecognitionModes(apiExtra.recognitionModes);
164         aidlExtra.confidenceLevel = apiExtra.coarseConfidenceLevel;
165         aidlExtra.levels = new ConfidenceLevel[apiExtra.confidenceLevels.length];
166         for (int i = 0; i < apiExtra.confidenceLevels.length; ++i) {
167             aidlExtra.levels[i] = api2aidlConfidenceLevel(apiExtra.confidenceLevels[i]);
168         }
169         return aidlExtra;
170     }
171 
aidl2apiPhraseRecognitionExtra( PhraseRecognitionExtra aidlExtra)172     public static SoundTrigger.KeyphraseRecognitionExtra aidl2apiPhraseRecognitionExtra(
173             PhraseRecognitionExtra aidlExtra) {
174         SoundTrigger.ConfidenceLevel[] apiLevels =
175                 new SoundTrigger.ConfidenceLevel[aidlExtra.levels.length];
176         for (int i = 0; i < aidlExtra.levels.length; ++i) {
177             apiLevels[i] = aidl2apiConfidenceLevel(aidlExtra.levels[i]);
178         }
179         return new SoundTrigger.KeyphraseRecognitionExtra(aidlExtra.id,
180                 aidl2apiRecognitionModes(aidlExtra.recognitionModes),
181                 aidlExtra.confidenceLevel, apiLevels);
182     }
183 
api2aidlConfidenceLevel( SoundTrigger.ConfidenceLevel apiLevel)184     public static ConfidenceLevel api2aidlConfidenceLevel(
185             SoundTrigger.ConfidenceLevel apiLevel) {
186         ConfidenceLevel aidlLevel = new ConfidenceLevel();
187         aidlLevel.levelPercent = apiLevel.confidenceLevel;
188         aidlLevel.userId = apiLevel.userId;
189         return aidlLevel;
190     }
191 
aidl2apiConfidenceLevel( ConfidenceLevel apiLevel)192     public static SoundTrigger.ConfidenceLevel aidl2apiConfidenceLevel(
193             ConfidenceLevel apiLevel) {
194         return new SoundTrigger.ConfidenceLevel(apiLevel.userId, apiLevel.levelPercent);
195     }
196 
aidl2apiRecognitionEvent( int modelHandle, int captureSession, RecognitionEvent aidlEvent)197     public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
198             int modelHandle, int captureSession, RecognitionEvent aidlEvent) {
199         // The API recognition event doesn't allow for a null audio format, even though it doesn't
200         // always make sense. We thus replace it with a default.
201         AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
202                 aidlEvent.audioConfig, true /*isInput*/);
203         return new SoundTrigger.GenericRecognitionEvent(
204                 aidlEvent.status,
205                 modelHandle, aidlEvent.captureAvailable, captureSession,
206                 aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData,
207                 audioFormat, aidlEvent.data, aidlEvent.recognitionStillActive);
208     }
209 
aidl2apiPhraseRecognitionEvent( int modelHandle, int captureSession, PhraseRecognitionEvent aidlEvent)210     public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
211             int modelHandle, int captureSession,
212             PhraseRecognitionEvent aidlEvent) {
213         SoundTrigger.KeyphraseRecognitionExtra[] apiExtras =
214                 new SoundTrigger.KeyphraseRecognitionExtra[aidlEvent.phraseExtras.length];
215         for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) {
216             apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]);
217         }
218         // The API recognition event doesn't allow for a null audio format, even though it doesn't
219         // always make sense. We thus replace it with a default.
220         AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
221                 aidlEvent.common.audioConfig, true /*isInput*/);
222         return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
223                 aidlEvent.common.captureAvailable,
224                 captureSession, aidlEvent.common.captureDelayMs,
225                 aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData,
226                 audioFormat, aidlEvent.common.data,
227                 apiExtras);
228     }
229 
230     // In case of a null input returns a non-null valid output.
aidl2apiAudioFormatWithDefault( @ullable AudioConfig audioConfig, boolean isInput)231     public static AudioFormat aidl2apiAudioFormatWithDefault(
232             @Nullable AudioConfig audioConfig, boolean isInput) {
233         if (audioConfig != null) {
234             return AidlConversion.aidl2api_AudioConfig_AudioFormat(audioConfig, isInput);
235         }
236         return new AudioFormat.Builder().build();
237     }
238 
api2aidlModelParameter(int apiParam)239     public static int api2aidlModelParameter(int apiParam) {
240         switch (apiParam) {
241             case ModelParams.THRESHOLD_FACTOR:
242                 return android.media.soundtrigger.ModelParameter.THRESHOLD_FACTOR;
243             default:
244                 return android.media.soundtrigger.ModelParameter.INVALID;
245         }
246     }
247 
aidl2apiModelParameterRange( @ullable ModelParameterRange aidlRange)248     public static SoundTrigger.ModelParamRange aidl2apiModelParameterRange(
249             @Nullable ModelParameterRange aidlRange) {
250         if (aidlRange == null) {
251             return null;
252         }
253         return new SoundTrigger.ModelParamRange(aidlRange.minInclusive, aidlRange.maxInclusive);
254     }
255 
aidl2apiAudioCapabilities(int aidlCapabilities)256     public static int aidl2apiAudioCapabilities(int aidlCapabilities) {
257         int result = 0;
258         if ((aidlCapabilities & AudioCapabilities.ECHO_CANCELLATION) != 0) {
259             result |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION;
260         }
261         if ((aidlCapabilities & AudioCapabilities.NOISE_SUPPRESSION) != 0) {
262             result |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION;
263         }
264         return result;
265     }
266 
api2aidlAudioCapabilities(int apiCapabilities)267     public static int api2aidlAudioCapabilities(int apiCapabilities) {
268         int result = 0;
269         if ((apiCapabilities & SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION)
270                 != 0) {
271             result |= AudioCapabilities.ECHO_CANCELLATION;
272         }
273         if ((apiCapabilities & SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION)
274                 != 0) {
275             result |= AudioCapabilities.NOISE_SUPPRESSION;
276         }
277         return result;
278     }
279 
byteArrayToSharedMemory(byte[] data, String name)280     private static @Nullable ParcelFileDescriptor byteArrayToSharedMemory(byte[] data, String name) {
281         if (data.length == 0) {
282             return null;
283         }
284 
285         try {
286             SharedMemory shmem = SharedMemory.create(name != null ? name : "", data.length);
287             ByteBuffer buffer = shmem.mapReadWrite();
288             buffer.put(data);
289             shmem.unmap(buffer);
290             ParcelFileDescriptor fd = shmem.getFdDup();
291             shmem.close();
292             return fd;
293         } catch (Exception e) {
294             throw new RuntimeException(e);
295         }
296     }
297 }
298