blob: 3d763e630bd0e922cb33a65713d1f59d2e703825 [file] [log] [blame]
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001/*
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
17package android.hardware.soundtrigger;
18
Nicholas Ambur38027cd2019-12-16 00:06:19 -080019import android.annotation.Nullable;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080020import android.media.AudioFormat;
21import android.media.audio.common.AudioConfig;
Nicholas Ambur7092a562019-12-16 11:18:55 -080022import android.media.soundtrigger_middleware.AudioCapabilities;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080023import android.media.soundtrigger_middleware.ConfidenceLevel;
24import android.media.soundtrigger_middleware.ModelParameterRange;
25import android.media.soundtrigger_middleware.Phrase;
26import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
27import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
28import android.media.soundtrigger_middleware.PhraseSoundModel;
29import android.media.soundtrigger_middleware.RecognitionConfig;
30import android.media.soundtrigger_middleware.RecognitionEvent;
31import android.media.soundtrigger_middleware.RecognitionMode;
32import android.media.soundtrigger_middleware.SoundModel;
33import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
34import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
Ytai Ben-Tsvid5065ba2020-02-27 15:36:05 -080035import android.os.SharedMemory;
36import android.system.ErrnoException;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080037
Ytai Ben-Tsvid5065ba2020-02-27 15:36:05 -080038import java.io.FileDescriptor;
39import java.nio.ByteBuffer;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080040import java.util.Arrays;
41import java.util.UUID;
42
43/** @hide */
44class ConversionUtil {
45 public static SoundTrigger.ModuleProperties aidl2apiModuleDescriptor(
46 SoundTriggerModuleDescriptor aidlDesc) {
47 SoundTriggerModuleProperties properties = aidlDesc.properties;
48 return new SoundTrigger.ModuleProperties(
49 aidlDesc.handle,
50 properties.implementor,
51 properties.description,
52 properties.uuid,
53 properties.version,
Nicholas Ambur38027cd2019-12-16 00:06:19 -080054 properties.supportedModelArch,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080055 properties.maxSoundModels,
56 properties.maxKeyPhrases,
57 properties.maxUsers,
58 aidl2apiRecognitionModes(properties.recognitionModes),
59 properties.captureTransition,
60 properties.maxBufferMs,
61 properties.concurrentCapture,
62 properties.powerConsumptionMw,
Nicholas Ambur7092a562019-12-16 11:18:55 -080063 properties.triggerInEvent,
64 aidl2apiAudioCapabilities(properties.audioCapabilities)
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080065 );
66 }
67
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
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
103 public static SoundModel api2aidlGenericSoundModel(SoundTrigger.GenericSoundModel apiModel) {
104 return api2aidlSoundModel(apiModel);
105 }
106
107 public static SoundModel api2aidlSoundModel(SoundTrigger.SoundModel apiModel) {
108 SoundModel aidlModel = new SoundModel();
109 aidlModel.type = apiModel.type;
110 aidlModel.uuid = api2aidlUuid(apiModel.uuid);
111 aidlModel.vendorUuid = api2aidlUuid(apiModel.vendorUuid);
Ytai Ben-Tsvid5065ba2020-02-27 15:36:05 -0800112 aidlModel.data = byteArrayToSharedMemory(apiModel.data, "SoundTrigger SoundModel");
113 aidlModel.dataSize = apiModel.data.length;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800114 return aidlModel;
115 }
116
117 public static String api2aidlUuid(UUID apiUuid) {
118 return apiUuid.toString();
119 }
120
121 public static PhraseSoundModel api2aidlPhraseSoundModel(
122 SoundTrigger.KeyphraseSoundModel apiModel) {
123 PhraseSoundModel aidlModel = new PhraseSoundModel();
124 aidlModel.common = api2aidlSoundModel(apiModel);
125 aidlModel.phrases = new Phrase[apiModel.keyphrases.length];
126 for (int i = 0; i < apiModel.keyphrases.length; ++i) {
127 aidlModel.phrases[i] = api2aidlPhrase(apiModel.keyphrases[i]);
128 }
129 return aidlModel;
130 }
131
132 public static Phrase api2aidlPhrase(SoundTrigger.Keyphrase apiPhrase) {
133 Phrase aidlPhrase = new Phrase();
134 aidlPhrase.id = apiPhrase.id;
135 aidlPhrase.recognitionModes = api2aidlRecognitionModes(apiPhrase.recognitionModes);
136 aidlPhrase.users = Arrays.copyOf(apiPhrase.users, apiPhrase.users.length);
Nicholas Amburef84fc42020-01-14 20:28:37 -0800137 aidlPhrase.locale = apiPhrase.locale.toLanguageTag();
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800138 aidlPhrase.text = apiPhrase.text;
139 return aidlPhrase;
140 }
141
142 public static RecognitionConfig api2aidlRecognitionConfig(
143 SoundTrigger.RecognitionConfig apiConfig) {
144 RecognitionConfig aidlConfig = new RecognitionConfig();
145 aidlConfig.captureRequested = apiConfig.captureRequested;
146 // apiConfig.allowMultipleTriggers is ignored by the lower layers.
147 aidlConfig.phraseRecognitionExtras =
148 new PhraseRecognitionExtra[apiConfig.keyphrases.length];
149 for (int i = 0; i < apiConfig.keyphrases.length; ++i) {
150 aidlConfig.phraseRecognitionExtras[i] = api2aidlPhraseRecognitionExtra(
151 apiConfig.keyphrases[i]);
152 }
153 aidlConfig.data = Arrays.copyOf(apiConfig.data, apiConfig.data.length);
Nicholas Ambur7092a562019-12-16 11:18:55 -0800154 aidlConfig.audioCapabilities = api2aidlAudioCapabilities(apiConfig.audioCapabilities);
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800155 return aidlConfig;
156 }
157
158 public static PhraseRecognitionExtra api2aidlPhraseRecognitionExtra(
159 SoundTrigger.KeyphraseRecognitionExtra apiExtra) {
160 PhraseRecognitionExtra aidlExtra = new PhraseRecognitionExtra();
161 aidlExtra.id = apiExtra.id;
162 aidlExtra.recognitionModes = api2aidlRecognitionModes(apiExtra.recognitionModes);
163 aidlExtra.confidenceLevel = apiExtra.coarseConfidenceLevel;
164 aidlExtra.levels = new ConfidenceLevel[apiExtra.confidenceLevels.length];
165 for (int i = 0; i < apiExtra.confidenceLevels.length; ++i) {
166 aidlExtra.levels[i] = api2aidlConfidenceLevel(apiExtra.confidenceLevels[i]);
167 }
168 return aidlExtra;
169 }
170
171 public static SoundTrigger.KeyphraseRecognitionExtra aidl2apiPhraseRecognitionExtra(
172 PhraseRecognitionExtra aidlExtra) {
173 SoundTrigger.ConfidenceLevel[] apiLevels =
174 new SoundTrigger.ConfidenceLevel[aidlExtra.levels.length];
175 for (int i = 0; i < aidlExtra.levels.length; ++i) {
176 apiLevels[i] = aidl2apiConfidenceLevel(aidlExtra.levels[i]);
177 }
178 return new SoundTrigger.KeyphraseRecognitionExtra(aidlExtra.id,
179 aidl2apiRecognitionModes(aidlExtra.recognitionModes),
180 aidlExtra.confidenceLevel, apiLevels);
181 }
182
183 public static ConfidenceLevel api2aidlConfidenceLevel(
184 SoundTrigger.ConfidenceLevel apiLevel) {
185 ConfidenceLevel aidlLevel = new ConfidenceLevel();
186 aidlLevel.levelPercent = apiLevel.confidenceLevel;
187 aidlLevel.userId = apiLevel.userId;
188 return aidlLevel;
189 }
190
191 public static SoundTrigger.ConfidenceLevel aidl2apiConfidenceLevel(
192 ConfidenceLevel apiLevel) {
193 return new SoundTrigger.ConfidenceLevel(apiLevel.userId, apiLevel.levelPercent);
194 }
195
196 public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
197 int modelHandle, RecognitionEvent aidlEvent) {
198 return new SoundTrigger.GenericRecognitionEvent(
199 aidlEvent.status,
200 modelHandle, aidlEvent.captureAvailable, aidlEvent.captureSession,
201 aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData,
202 aidl2apiAudioFormat(aidlEvent.audioConfig), aidlEvent.data);
203 }
204
205 public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
206 int modelHandle,
207 PhraseRecognitionEvent aidlEvent) {
208 SoundTrigger.KeyphraseRecognitionExtra[] apiExtras =
209 new SoundTrigger.KeyphraseRecognitionExtra[aidlEvent.phraseExtras.length];
210 for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) {
211 apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]);
212 }
213 return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
214 aidlEvent.common.captureAvailable,
215 aidlEvent.common.captureSession, aidlEvent.common.captureDelayMs,
216 aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData,
217 aidl2apiAudioFormat(aidlEvent.common.audioConfig), aidlEvent.common.data,
218 apiExtras);
219 }
220
221 public static AudioFormat aidl2apiAudioFormat(AudioConfig audioConfig) {
222 AudioFormat.Builder apiBuilder = new AudioFormat.Builder();
223 apiBuilder.setSampleRate(audioConfig.sampleRateHz);
224 apiBuilder.setChannelMask(aidl2apiChannelInMask(audioConfig.channelMask));
225 apiBuilder.setEncoding(aidl2apiEncoding(audioConfig.format));
226 return apiBuilder.build();
227 }
228
229 public static int aidl2apiEncoding(int aidlFormat) {
230 switch (aidlFormat) {
231 case android.media.audio.common.AudioFormat.PCM
232 | android.media.audio.common.AudioFormat.PCM_SUB_16_BIT:
233 return AudioFormat.ENCODING_PCM_16BIT;
234
235 case android.media.audio.common.AudioFormat.PCM
236 | android.media.audio.common.AudioFormat.PCM_SUB_8_BIT:
237 return AudioFormat.ENCODING_PCM_8BIT;
238
239 case android.media.audio.common.AudioFormat.PCM
240 | android.media.audio.common.AudioFormat.PCM_SUB_FLOAT:
241 case android.media.audio.common.AudioFormat.PCM
242 | android.media.audio.common.AudioFormat.PCM_SUB_8_24_BIT:
243 case android.media.audio.common.AudioFormat.PCM
244 | android.media.audio.common.AudioFormat.PCM_SUB_24_BIT_PACKED:
245 case android.media.audio.common.AudioFormat.PCM
246 | android.media.audio.common.AudioFormat.PCM_SUB_32_BIT:
247 return AudioFormat.ENCODING_PCM_FLOAT;
248
249 case android.media.audio.common.AudioFormat.AC3:
250 return AudioFormat.ENCODING_AC3;
251
252 case android.media.audio.common.AudioFormat.E_AC3:
253 return AudioFormat.ENCODING_E_AC3;
254
255 case android.media.audio.common.AudioFormat.DTS:
256 return AudioFormat.ENCODING_DTS;
257
258 case android.media.audio.common.AudioFormat.DTS_HD:
259 return AudioFormat.ENCODING_DTS_HD;
260
261 case android.media.audio.common.AudioFormat.MP3:
262 return AudioFormat.ENCODING_MP3;
263
264 case android.media.audio.common.AudioFormat.AAC
265 | android.media.audio.common.AudioFormat.AAC_SUB_LC:
266 return AudioFormat.ENCODING_AAC_LC;
267
268 case android.media.audio.common.AudioFormat.AAC
269 | android.media.audio.common.AudioFormat.AAC_SUB_HE_V1:
270 return AudioFormat.ENCODING_AAC_HE_V1;
271
272 case android.media.audio.common.AudioFormat.AAC
273 | android.media.audio.common.AudioFormat.AAC_SUB_HE_V2:
274 return AudioFormat.ENCODING_AAC_HE_V2;
275
276 case android.media.audio.common.AudioFormat.IEC61937:
277 return AudioFormat.ENCODING_IEC61937;
278
279 case android.media.audio.common.AudioFormat.DOLBY_TRUEHD:
280 return AudioFormat.ENCODING_DOLBY_TRUEHD;
281
282 case android.media.audio.common.AudioFormat.AAC
283 | android.media.audio.common.AudioFormat.AAC_SUB_ELD:
284 return AudioFormat.ENCODING_AAC_ELD;
285
286 case android.media.audio.common.AudioFormat.AAC
287 | android.media.audio.common.AudioFormat.AAC_SUB_XHE:
288 return AudioFormat.ENCODING_AAC_XHE;
289
290 case android.media.audio.common.AudioFormat.AC4:
291 return AudioFormat.ENCODING_AC4;
292
293 case android.media.audio.common.AudioFormat.E_AC3
294 | android.media.audio.common.AudioFormat.E_AC3_SUB_JOC:
295 return AudioFormat.ENCODING_E_AC3_JOC;
296
297 case android.media.audio.common.AudioFormat.MAT:
298 case android.media.audio.common.AudioFormat.MAT
299 | android.media.audio.common.AudioFormat.MAT_SUB_1_0:
300 case android.media.audio.common.AudioFormat.MAT
301 | android.media.audio.common.AudioFormat.MAT_SUB_2_0:
302 case android.media.audio.common.AudioFormat.MAT
303 | android.media.audio.common.AudioFormat.MAT_SUB_2_1:
304 return AudioFormat.ENCODING_DOLBY_MAT;
305
306 case android.media.audio.common.AudioFormat.DEFAULT:
307 return AudioFormat.ENCODING_DEFAULT;
308
309 default:
310 return AudioFormat.ENCODING_INVALID;
311 }
312 }
313
314 public static int api2aidlModelParameter(int apiParam) {
315 switch (apiParam) {
316 case ModelParams.THRESHOLD_FACTOR:
317 return android.media.soundtrigger_middleware.ModelParameter.THRESHOLD_FACTOR;
318 default:
319 return android.media.soundtrigger_middleware.ModelParameter.INVALID;
320 }
321 }
322
323 public static int aidl2apiChannelInMask(int aidlMask) {
324 // We're assuming AudioFormat.CHANNEL_IN_* constants are kept in sync with
325 // android.media.audio.common.AudioChannelMask.
326 return aidlMask;
327 }
328
329 public static SoundTrigger.ModelParamRange aidl2apiModelParameterRange(
330 @Nullable ModelParameterRange aidlRange) {
331 if (aidlRange == null) {
332 return null;
333 }
334 return new SoundTrigger.ModelParamRange(aidlRange.minInclusive, aidlRange.maxInclusive);
335 }
Nicholas Ambur7092a562019-12-16 11:18:55 -0800336
337 public static int aidl2apiAudioCapabilities(int aidlCapabilities) {
338 int result = 0;
339 if ((aidlCapabilities & AudioCapabilities.ECHO_CANCELLATION) != 0) {
Nicholas Amburce5cd842020-02-04 13:39:59 -0800340 result |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION;
Nicholas Ambur7092a562019-12-16 11:18:55 -0800341 }
342 if ((aidlCapabilities & AudioCapabilities.NOISE_SUPPRESSION) != 0) {
Nicholas Amburce5cd842020-02-04 13:39:59 -0800343 result |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION;
Nicholas Ambur7092a562019-12-16 11:18:55 -0800344 }
345 return result;
346 }
347
348 public static int api2aidlAudioCapabilities(int apiCapabilities) {
349 int result = 0;
Nicholas Amburce5cd842020-02-04 13:39:59 -0800350 if ((apiCapabilities & SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION)
351 != 0) {
Nicholas Ambur7092a562019-12-16 11:18:55 -0800352 result |= AudioCapabilities.ECHO_CANCELLATION;
353 }
Nicholas Amburce5cd842020-02-04 13:39:59 -0800354 if ((apiCapabilities & SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_NOISE_SUPPRESSION)
355 != 0) {
Nicholas Ambur7092a562019-12-16 11:18:55 -0800356 result |= AudioCapabilities.NOISE_SUPPRESSION;
357 }
358 return result;
359 }
Ytai Ben-Tsvid5065ba2020-02-27 15:36:05 -0800360
361 private static @Nullable FileDescriptor byteArrayToSharedMemory(byte[] data, String name) {
362 if (data.length == 0) {
363 return null;
364 }
365
366 try {
367 SharedMemory shmem = SharedMemory.create(name != null ? name : "", data.length);
368 ByteBuffer buffer = shmem.mapReadWrite();
369 buffer.put(data);
370 shmem.unmap(buffer);
371 return shmem.getFileDescriptor();
372 } catch (ErrnoException e) {
373 throw new RuntimeException(e);
374 }
375 }
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800376}