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 #define LOG_TAG "SoundTriggerHw"
17
18 #include "SoundTriggerHw.h"
19
20 #include <android/hidl/allocator/1.0/IAllocator.h>
21 #include <android/log.h>
22 #include <hidlmemory/mapping.h>
23 #include <utility>
24
25 using android::hardware::hidl_memory;
26 using android::hidl::allocator::V1_0::IAllocator;
27 using android::hidl::memory::V1_0::IMemory;
28
29 namespace android {
30 namespace hardware {
31 namespace soundtrigger {
32 namespace V2_3 {
33 namespace implementation {
34
35 /**
36 * According to the HIDL C++ Users Guide: client and server implementations
37 * should never directly refer to anything other than the interface header
38 * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so
39 * this V2_3 implementation copies the previous implementations and
40 * then adds the new implementation.
41 */
42
43 // Begin V2_0 implementation, copied from
44 // hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
45
46 // static
soundModelCallback_(struct sound_trigger_model_event * halEvent,void * cookie)47 void soundModelCallback_(struct sound_trigger_model_event* halEvent, void* cookie) {
48 if (halEvent == NULL) {
49 ALOGW("soundModelCallback called with NULL event");
50 return;
51 }
52 sp<SoundTriggerHw::SoundModelClient> client =
53 wp<SoundTriggerHw::SoundModelClient>(
54 static_cast<SoundTriggerHw::SoundModelClient*>(cookie))
55 .promote();
56 if (client == 0) {
57 ALOGW("soundModelCallback called on stale client");
58 return;
59 }
60 if (halEvent->model != client->getHalHandle()) {
61 ALOGW("soundModelCallback call with wrong handle %d on client with handle %d",
62 (int)halEvent->model, (int)client->getHalHandle());
63 return;
64 }
65
66 client->soundModelCallback(halEvent);
67 }
68
69 // static
recognitionCallback_(struct sound_trigger_recognition_event * halEvent,void * cookie)70 void recognitionCallback_(struct sound_trigger_recognition_event* halEvent, void* cookie) {
71 if (halEvent == NULL) {
72 ALOGW("recognitionCallback call NULL event");
73 return;
74 }
75 sp<SoundTriggerHw::SoundModelClient> client =
76 wp<SoundTriggerHw::SoundModelClient>(
77 static_cast<SoundTriggerHw::SoundModelClient*>(cookie))
78 .promote();
79 if (client == 0) {
80 ALOGW("recognitionCallback called on stale client");
81 return;
82 }
83
84 client->recognitionCallback(halEvent);
85 }
86
getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb)87 Return<void> SoundTriggerHw::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) {
88 ALOGV("getProperties() mHwDevice %p", mHwDevice);
89 int ret;
90 struct sound_trigger_properties halProperties;
91 V2_0::ISoundTriggerHw::Properties properties;
92
93 if (mHwDevice == NULL) {
94 ret = -ENODEV;
95 goto exit;
96 }
97
98 ret = mHwDevice->get_properties(mHwDevice, &halProperties);
99
100 convertPropertiesFromHal(&properties, &halProperties);
101
102 ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(),
103 properties.recognitionModes);
104
105 exit:
106 _hidl_cb(ret, properties);
107 return Void();
108 }
109
doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel & soundModel,sp<SoundTriggerHw::SoundModelClient> client)110 int SoundTriggerHw::doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
111 sp<SoundTriggerHw::SoundModelClient> client) {
112 int32_t ret = 0;
113 struct sound_trigger_sound_model* halSoundModel;
114
115 ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size());
116
117 if (mHwDevice == NULL) {
118 ret = -ENODEV;
119 goto exit;
120 }
121
122 halSoundModel = convertSoundModelToHal(&soundModel);
123 if (halSoundModel == NULL) {
124 ret = -EINVAL;
125 goto exit;
126 }
127
128 sound_model_handle_t halHandle;
129 ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback_, client.get(),
130 &halHandle);
131
132 free(halSoundModel);
133
134 if (ret != 0) {
135 goto exit;
136 }
137
138 client->setHalHandle(halHandle);
139 {
140 AutoMutex lock(mLock);
141 mClients.add(client->getId(), client);
142 }
143
144 exit:
145 return ret;
146 }
147
loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel & soundModel,const sp<V2_0::ISoundTriggerHwCallback> & callback,V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,ISoundTriggerHw::loadSoundModel_cb _hidl_cb)148 Return<void> SoundTriggerHw::loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
149 const sp<V2_0::ISoundTriggerHwCallback>& callback,
150 V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
151 ISoundTriggerHw::loadSoundModel_cb _hidl_cb) {
152 sp<SoundTriggerHw::SoundModelClient> client =
153 new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
154 _hidl_cb(doLoadSoundModel(soundModel, client), client->getId());
155 return Void();
156 }
157
loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel & soundModel,const sp<V2_0::ISoundTriggerHwCallback> & callback,V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb)158 Return<void> SoundTriggerHw::loadPhraseSoundModel(
159 const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
160 const sp<V2_0::ISoundTriggerHwCallback>& callback,
161 V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
162 ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) {
163 sp<SoundTriggerHw::SoundModelClient> client =
164 new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
165 _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel, client),
166 client->getId());
167 return Void();
168 }
169
unloadSoundModel(int32_t modelHandle)170 Return<int32_t> SoundTriggerHw::unloadSoundModel(int32_t modelHandle) {
171 int32_t ret;
172 sp<SoundTriggerHw::SoundModelClient> client;
173
174 if (mHwDevice == NULL) {
175 ret = -ENODEV;
176 goto exit;
177 }
178
179 {
180 AutoMutex lock(mLock);
181 client = mClients.valueFor(modelHandle);
182 if (client == 0) {
183 ret = -ENOSYS;
184 goto exit;
185 }
186 }
187
188 ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle());
189
190 mClients.removeItem(modelHandle);
191
192 exit:
193 return ret;
194 }
195
startRecognition(int32_t modelHandle,const V2_0::ISoundTriggerHw::RecognitionConfig & config,const sp<V2_0::ISoundTriggerHwCallback> &,int32_t)196 Return<int32_t> SoundTriggerHw::startRecognition(
197 int32_t modelHandle, const V2_0::ISoundTriggerHw::RecognitionConfig& config,
198 const sp<V2_0::ISoundTriggerHwCallback>& /* callback */, int32_t /* cookie */) {
199 int32_t ret;
200 sp<SoundTriggerHw::SoundModelClient> client;
201 struct sound_trigger_recognition_config* halConfig;
202
203 if (mHwDevice == NULL) {
204 ret = -ENODEV;
205 goto exit;
206 }
207
208 {
209 AutoMutex lock(mLock);
210 client = mClients.valueFor(modelHandle);
211 if (client == 0) {
212 ret = -ENOSYS;
213 goto exit;
214 }
215 }
216
217 halConfig =
218 convertRecognitionConfigToHal((const V2_0::ISoundTriggerHw::RecognitionConfig*)&config);
219
220 if (halConfig == NULL) {
221 ret = -EINVAL;
222 goto exit;
223 }
224 ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig,
225 recognitionCallback_, client.get());
226
227 free(halConfig);
228
229 exit:
230 return ret;
231 }
232
stopRecognition(int32_t modelHandle)233 Return<int32_t> SoundTriggerHw::stopRecognition(int32_t modelHandle) {
234 int32_t ret;
235 sp<SoundTriggerHw::SoundModelClient> client;
236 if (mHwDevice == NULL) {
237 ret = -ENODEV;
238 goto exit;
239 }
240
241 {
242 AutoMutex lock(mLock);
243 client = mClients.valueFor(modelHandle);
244 if (client == 0) {
245 ret = -ENOSYS;
246 goto exit;
247 }
248 }
249
250 ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle());
251
252 exit:
253 return ret;
254 }
255
stopAllRecognitions()256 Return<int32_t> SoundTriggerHw::stopAllRecognitions() {
257 int32_t ret;
258 if (mHwDevice == NULL) {
259 ret = -ENODEV;
260 goto exit;
261 }
262
263 ret = mHwDevice->stop_all_recognitions(mHwDevice);
264
265 exit:
266 return ret;
267 }
268
SoundTriggerHw()269 SoundTriggerHw::SoundTriggerHw() : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {}
270
onFirstRef()271 void SoundTriggerHw::onFirstRef() {
272 const hw_module_t* mod;
273 int rc;
274
275 rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
276 if (rc != 0) {
277 ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID,
278 mModuleName, strerror(-rc));
279 return;
280 }
281 rc = sound_trigger_hw_device_open(mod, &mHwDevice);
282 if (rc != 0) {
283 ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
284 SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
285 mHwDevice = NULL;
286 return;
287 }
288 if (mHwDevice->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_1_3) {
289 ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
290 sound_trigger_hw_device_close(mHwDevice);
291 mHwDevice = NULL;
292 return;
293 }
294
295 ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
296 }
297
~SoundTriggerHw()298 SoundTriggerHw::~SoundTriggerHw() {
299 if (mHwDevice != NULL) {
300 sound_trigger_hw_device_close(mHwDevice);
301 }
302 }
303
nextUniqueModelId()304 uint32_t SoundTriggerHw::nextUniqueModelId() {
305 uint32_t modelId = 0;
306 {
307 AutoMutex lock(mLock);
308 do {
309 modelId = atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1,
310 memory_order_acq_rel);
311 } while (mClients.valueFor(modelId) != 0 && modelId != 0);
312 }
313 LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu",
314 mClients.size());
315 return modelId;
316 }
317
convertUuidFromHal(Uuid * uuid,const sound_trigger_uuid_t * halUuid)318 void SoundTriggerHw::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) {
319 uuid->timeLow = halUuid->timeLow;
320 uuid->timeMid = halUuid->timeMid;
321 uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
322 uuid->variantAndClockSeqHigh = halUuid->clockSeq;
323 memcpy(&uuid->node[0], &halUuid->node[0], 6);
324 }
325
convertUuidToHal(sound_trigger_uuid_t * halUuid,const Uuid * uuid)326 void SoundTriggerHw::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) {
327 halUuid->timeLow = uuid->timeLow;
328 halUuid->timeMid = uuid->timeMid;
329 halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
330 halUuid->clockSeq = uuid->variantAndClockSeqHigh;
331 memcpy(&halUuid->node[0], &uuid->node[0], 6);
332 }
333
convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties * properties,const struct sound_trigger_properties * halProperties)334 void SoundTriggerHw::convertPropertiesFromHal(
335 V2_0::ISoundTriggerHw::Properties* properties,
336 const struct sound_trigger_properties* halProperties) {
337 properties->implementor = halProperties->implementor;
338 properties->description = halProperties->description;
339 properties->version = halProperties->version;
340 convertUuidFromHal(&properties->uuid, &halProperties->uuid);
341 properties->maxSoundModels = halProperties->max_sound_models;
342 properties->maxKeyPhrases = halProperties->max_key_phrases;
343 properties->maxUsers = halProperties->max_users;
344 properties->recognitionModes = halProperties->recognition_modes;
345 properties->captureTransition = halProperties->capture_transition;
346 properties->maxBufferMs = halProperties->max_buffer_ms;
347 properties->concurrentCapture = halProperties->concurrent_capture;
348 properties->triggerInEvent = halProperties->trigger_in_event;
349 properties->powerConsumptionMw = halProperties->power_consumption_mw;
350 }
351
convertPropertiesFromHal(V2_3::Properties * properties,const struct sound_trigger_properties_header * header)352 void SoundTriggerHw::convertPropertiesFromHal(
353 V2_3::Properties* properties, const struct sound_trigger_properties_header* header) {
354 if (header->version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_3) {
355 const struct sound_trigger_properties_extended_1_3* halProperties =
356 (const struct sound_trigger_properties_extended_1_3*)header;
357 convertPropertiesFromHal(&properties->base, &halProperties->base);
358 properties->supportedModelArch = halProperties->supported_model_arch;
359 properties->audioCapabilities = halProperties->audio_capabilities;
360 }
361 }
362
convertTriggerPhraseToHal(struct sound_trigger_phrase * halTriggerPhrase,const ISoundTriggerHw::Phrase * triggerPhrase)363 void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
364 const ISoundTriggerHw::Phrase* triggerPhrase) {
365 halTriggerPhrase->id = triggerPhrase->id;
366 halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
367 unsigned int i;
368
369 halTriggerPhrase->num_users =
370 std::min((int)triggerPhrase->users.size(), SOUND_TRIGGER_MAX_USERS);
371 for (i = 0; i < halTriggerPhrase->num_users; i++) {
372 halTriggerPhrase->users[i] = triggerPhrase->users[i];
373 }
374
375 strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
376 strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
377 }
378
convertSoundModelToHal(const V2_0::ISoundTriggerHw::SoundModel * soundModel)379 struct sound_trigger_sound_model* SoundTriggerHw::convertSoundModelToHal(
380 const V2_0::ISoundTriggerHw::SoundModel* soundModel) {
381 struct sound_trigger_sound_model* halModel = NULL;
382 if (soundModel->type == V2_0::SoundModelType::KEYPHRASE) {
383 size_t allocSize =
384 sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
385 struct sound_trigger_phrase_sound_model* halKeyPhraseModel =
386 static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize));
387 LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
388 "malloc failed for size %zu in convertSoundModelToHal PHRASE",
389 allocSize);
390
391 const V2_0::ISoundTriggerHw::PhraseSoundModel* keyPhraseModel =
392 reinterpret_cast<const V2_0::ISoundTriggerHw::PhraseSoundModel*>(soundModel);
393
394 size_t i;
395 for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
396 convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]);
397 }
398 halKeyPhraseModel->num_phrases = (unsigned int)i;
399 halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel);
400 halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
401 } else {
402 size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
403 halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize));
404 LOG_ALWAYS_FATAL_IF(halModel == NULL,
405 "malloc failed for size %zu in convertSoundModelToHal GENERIC",
406 allocSize);
407
408 halModel->data_offset = sizeof(struct sound_trigger_sound_model);
409 }
410 halModel->type = (sound_trigger_sound_model_type_t)soundModel->type;
411 convertUuidToHal(&halModel->uuid, &soundModel->uuid);
412 convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
413 halModel->data_size = soundModel->data.size();
414 uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset;
415 const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]);
416 memcpy(dst, src, soundModel->data.size());
417
418 return halModel;
419 }
420
convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra * halExtra,const V2_0::PhraseRecognitionExtra * extra)421 void SoundTriggerHw::convertPhraseRecognitionExtraToHal(
422 struct sound_trigger_phrase_recognition_extra* halExtra,
423 const V2_0::PhraseRecognitionExtra* extra) {
424 halExtra->id = extra->id;
425 halExtra->recognition_modes = extra->recognitionModes;
426 halExtra->confidence_level = extra->confidenceLevel;
427
428 unsigned int i;
429 for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
430 halExtra->levels[i].user_id = extra->levels[i].userId;
431 halExtra->levels[i].level = extra->levels[i].levelPercent;
432 }
433 halExtra->num_levels = i;
434 }
435
convertRecognitionConfigToHal(const V2_0::ISoundTriggerHw::RecognitionConfig * config)436 struct sound_trigger_recognition_config* SoundTriggerHw::convertRecognitionConfigToHal(
437 const V2_0::ISoundTriggerHw::RecognitionConfig* config) {
438 size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
439 struct sound_trigger_recognition_config* halConfig =
440 static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize));
441
442 LOG_ALWAYS_FATAL_IF(halConfig == NULL,
443 "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize);
444
445 halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
446 halConfig->capture_device = (audio_devices_t)config->captureDevice;
447 halConfig->capture_requested = config->captureRequested;
448
449 unsigned int i;
450 for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
451 convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]);
452 }
453 halConfig->num_phrases = i;
454
455 halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
456 halConfig->data_size = config->data.size();
457 uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset;
458 const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]);
459 memcpy(dst, src, config->data.size());
460 return halConfig;
461 }
462
convertRecognitionConfigToHalHeader(const V2_3::RecognitionConfig * config)463 struct sound_trigger_recognition_config_header* SoundTriggerHw::convertRecognitionConfigToHalHeader(
464 const V2_3::RecognitionConfig* config) {
465 sp<IMemory> memory;
466 const V2_1::ISoundTriggerHw::RecognitionConfig* config_2_1 = &config->base;
467 const V2_0::ISoundTriggerHw::RecognitionConfig* config_2_0 = &config_2_1->header;
468
469 size_t allocSize =
470 sizeof(struct sound_trigger_recognition_config_extended_1_3) + config_2_1->data.size();
471 struct sound_trigger_recognition_config_extended_1_3* halConfigExtended =
472 static_cast<struct sound_trigger_recognition_config_extended_1_3*>(malloc(allocSize));
473 LOG_ALWAYS_FATAL_IF(halConfigExtended == nullptr,
474 "malloc failed for size %zu in convertRecognitionConfigToHalHeader",
475 allocSize);
476 halConfigExtended->header.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_3;
477 halConfigExtended->header.size = allocSize;
478
479 struct sound_trigger_recognition_config* halConfigBase = &halConfigExtended->base;
480
481 halConfigBase->capture_handle = (audio_io_handle_t)config_2_0->captureHandle;
482 halConfigBase->capture_device = (audio_devices_t)config_2_0->captureDevice;
483 halConfigBase->capture_requested = config_2_0->captureRequested;
484
485 unsigned int i;
486 for (i = 0; i < config_2_0->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
487 convertPhraseRecognitionExtraToHal(&halConfigBase->phrases[i], &config_2_0->phrases[i]);
488 }
489 halConfigBase->num_phrases = i;
490
491 halConfigBase->data_offset = sizeof(struct sound_trigger_recognition_config_extended_1_3);
492 halConfigBase->data_size = config_2_1->data.size();
493 if (config_2_1->data.size() != 0) {
494 memory = mapMemory(config_2_1->data);
495 LOG_ALWAYS_FATAL_IF(memory == nullptr,
496 "failed to map config memory in convertRecognitionConfigToHalHeader");
497 memory->read();
498
499 uint8_t* dst = reinterpret_cast<uint8_t*>(halConfigExtended) + halConfigBase->data_offset;
500 const uint8_t* src = static_cast<const uint8_t*>(static_cast<void*>(memory->getPointer()));
501 memcpy(dst, src, config_2_1->data.size());
502
503 memory->commit();
504 }
505
506 halConfigExtended->audio_capabilities = config->audioCapabilities;
507
508 return &halConfigExtended->header;
509 }
510
511 // static
convertSoundModelEventFromHal(V2_0::ISoundTriggerHwCallback::ModelEvent * event,const struct sound_trigger_model_event * halEvent)512 void SoundTriggerHw::convertSoundModelEventFromHal(
513 V2_0::ISoundTriggerHwCallback::ModelEvent* event,
514 const struct sound_trigger_model_event* halEvent) {
515 event->status = (V2_0::ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
516 // event->model to be remapped by called
517 event->data.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) +
518 halEvent->data_offset,
519 halEvent->data_size);
520 }
521
522 // static
convertPhaseRecognitionEventFromHal(V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent * event,const struct sound_trigger_phrase_recognition_event * halEvent)523 void SoundTriggerHw::convertPhaseRecognitionEventFromHal(
524 V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
525 const struct sound_trigger_phrase_recognition_event* halEvent) {
526 event->phraseExtras.resize(halEvent->num_phrases);
527 for (unsigned int i = 0; i < halEvent->num_phrases; i++) {
528 convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]);
529 }
530 convertRecognitionEventFromHal(&event->common, &halEvent->common);
531 }
532
533 // static
convertRecognitionEventFromHal(V2_0::ISoundTriggerHwCallback::RecognitionEvent * event,const struct sound_trigger_recognition_event * halEvent)534 void SoundTriggerHw::convertRecognitionEventFromHal(
535 V2_0::ISoundTriggerHwCallback::RecognitionEvent* event,
536 const struct sound_trigger_recognition_event* halEvent) {
537 event->status = static_cast<V2_0::ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
538 event->type = static_cast<V2_0::SoundModelType>(halEvent->type);
539 // event->model to be remapped by called
540 event->captureAvailable = halEvent->capture_available;
541 event->captureSession = halEvent->capture_session;
542 event->captureDelayMs = halEvent->capture_delay_ms;
543 event->capturePreambleMs = halEvent->capture_preamble_ms;
544 event->triggerInData = halEvent->trigger_in_data;
545 event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
546 event->audioConfig.channelMask =
547 (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
548 event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
549 event->data.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) +
550 halEvent->data_offset,
551 halEvent->data_size);
552 }
553
554 // static
convertPhraseRecognitionExtraFromHal(V2_0::PhraseRecognitionExtra * extra,const struct sound_trigger_phrase_recognition_extra * halExtra)555 void SoundTriggerHw::convertPhraseRecognitionExtraFromHal(
556 V2_0::PhraseRecognitionExtra* extra,
557 const struct sound_trigger_phrase_recognition_extra* halExtra) {
558 extra->id = halExtra->id;
559 extra->recognitionModes = halExtra->recognition_modes;
560 extra->confidenceLevel = halExtra->confidence_level;
561
562 extra->levels.resize(halExtra->num_levels);
563 for (unsigned int i = 0; i < halExtra->num_levels; i++) {
564 extra->levels[i].userId = halExtra->levels[i].user_id;
565 extra->levels[i].levelPercent = halExtra->levels[i].level;
566 }
567 }
568
recognitionCallback(struct sound_trigger_recognition_event * halEvent)569 void SoundTriggerHw::SoundModelClient_2_0::recognitionCallback(
570 struct sound_trigger_recognition_event* halEvent) {
571 if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
572 V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
573 convertPhaseRecognitionEventFromHal(
574 &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
575 event.common.model = mId;
576 mCallback->phraseRecognitionCallback(event, mCookie);
577 } else {
578 V2_0::ISoundTriggerHwCallback::RecognitionEvent event;
579 convertRecognitionEventFromHal(&event, halEvent);
580 event.model = mId;
581 mCallback->recognitionCallback(event, mCookie);
582 }
583 }
584
soundModelCallback(struct sound_trigger_model_event * halEvent)585 void SoundTriggerHw::SoundModelClient_2_0::soundModelCallback(
586 struct sound_trigger_model_event* halEvent) {
587 V2_0::ISoundTriggerHwCallback::ModelEvent event;
588 convertSoundModelEventFromHal(&event, halEvent);
589 event.model = mId;
590 mCallback->soundModelCallback(event, mCookie);
591 }
592
593 // Begin V2_1 implementation, copied from
594 // hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.cpp
595
596 namespace {
597
598 // Backs up by the vector with the contents of shared memory.
599 // It is assumed that the passed hidl_vector is empty, so it's
600 // not cleared if the memory is a null object.
601 // The caller needs to keep the returned sp<IMemory> as long as
602 // the data is needed.
memoryAsVector(const hidl_memory & m,hidl_vec<uint8_t> * vec)603 std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) {
604 sp<IMemory> memory;
605 if (m.size() == 0) {
606 return std::make_pair(true, memory);
607 }
608 memory = mapMemory(m);
609 if (memory != nullptr) {
610 memory->read();
611 vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())),
612 memory->getSize());
613 return std::make_pair(true, memory);
614 }
615 ALOGE("%s: Could not map HIDL memory to IMemory", __func__);
616 return std::make_pair(false, memory);
617 }
618
619 // Moves the data from the vector into allocated shared memory,
620 // emptying the vector.
621 // It is assumed that the passed hidl_memory is a null object, so it's
622 // not reset if the vector is empty.
623 // The caller needs to keep the returned sp<IMemory> as long as
624 // the data is needed.
moveVectorToMemory(hidl_vec<uint8_t> * v,hidl_memory * mem)625 std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) {
626 sp<IMemory> memory;
627 if (v->size() == 0) {
628 return std::make_pair(true, memory);
629 }
630 sp<IAllocator> ashmem = IAllocator::getService("ashmem");
631 if (ashmem == 0) {
632 ALOGE("Failed to retrieve ashmem allocator service");
633 return std::make_pair(false, memory);
634 }
635 bool success = false;
636 Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) {
637 success = s;
638 if (success) *mem = m;
639 });
640 if (r.isOk() && success) {
641 memory = hardware::mapMemory(*mem);
642 if (memory != 0) {
643 memory->update();
644 memcpy(memory->getPointer(), v->data(), v->size());
645 memory->commit();
646 v->resize(0);
647 return std::make_pair(true, memory);
648 } else {
649 ALOGE("Failed to map allocated ashmem");
650 }
651 } else {
652 ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size());
653 }
654 return std::make_pair(false, memory);
655 }
656
657 } // namespace
658
loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel & soundModel,const sp<V2_1::ISoundTriggerHwCallback> & callback,int32_t cookie,V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb)659 Return<void> SoundTriggerHw::loadSoundModel_2_1(
660 const V2_1::ISoundTriggerHw::SoundModel& soundModel,
661 const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
662 V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) {
663 // It is assumed that legacy data vector is empty, thus making copy is cheap.
664 V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header);
665 auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data);
666 if (result.first) {
667 sp<SoundModelClient> client =
668 new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
669 _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId());
670 return Void();
671 }
672 _hidl_cb(-ENOMEM, 0);
673 return Void();
674 }
675
loadPhraseSoundModel_2_1(const V2_1::ISoundTriggerHw::PhraseSoundModel & soundModel,const sp<V2_1::ISoundTriggerHwCallback> & callback,int32_t cookie,V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb)676 Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1(
677 const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
678 const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
679 V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) {
680 V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0;
681 // It is assumed that legacy data vector is empty, thus making copy is cheap.
682 soundModel_2_0.common = soundModel.common.header;
683 // Avoid copying phrases data.
684 soundModel_2_0.phrases.setToExternal(
685 const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()),
686 soundModel.phrases.size());
687 auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data);
688 if (result.first) {
689 sp<SoundModelClient> client =
690 new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
691 _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client),
692 client->getId());
693 return Void();
694 }
695 _hidl_cb(-ENOMEM, 0);
696 return Void();
697 }
698
startRecognition_2_1(int32_t modelHandle,const V2_1::ISoundTriggerHw::RecognitionConfig & config,const sp<V2_1::ISoundTriggerHwCallback> & callback,int32_t cookie)699 Return<int32_t> SoundTriggerHw::startRecognition_2_1(
700 int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config,
701 const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie) {
702 // It is assumed that legacy data vector is empty, thus making copy is cheap.
703 V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header);
704 auto result = memoryAsVector(config.data, &config_2_0.data);
705 return result.first ? startRecognition(modelHandle, config_2_0, callback, cookie)
706 : Return<int32_t>(-ENOMEM);
707 }
708
recognitionCallback(struct sound_trigger_recognition_event * halEvent)709 void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback(
710 struct sound_trigger_recognition_event* halEvent) {
711 if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
712 V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0;
713 convertPhaseRecognitionEventFromHal(
714 &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
715 event_2_0.common.model = mId;
716 V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
717 event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(),
718 event_2_0.phraseExtras.size());
719 auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data);
720 if (result.first) {
721 // The data vector is now empty, thus copying is cheap.
722 event.common.header = event_2_0.common;
723 mCallback->phraseRecognitionCallback_2_1(event, mCookie);
724 }
725 } else {
726 V2_1::ISoundTriggerHwCallback::RecognitionEvent event;
727 convertRecognitionEventFromHal(&event.header, halEvent);
728 event.header.model = mId;
729 auto result = moveVectorToMemory(&event.header.data, &event.data);
730 if (result.first) {
731 mCallback->recognitionCallback_2_1(event, mCookie);
732 }
733 }
734 }
735
soundModelCallback(struct sound_trigger_model_event * halEvent)736 void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback(
737 struct sound_trigger_model_event* halEvent) {
738 V2_1::ISoundTriggerHwCallback::ModelEvent event;
739 convertSoundModelEventFromHal(&event.header, halEvent);
740 event.header.model = mId;
741 auto result = moveVectorToMemory(&event.header.data, &event.data);
742 if (result.first) {
743 mCallback->soundModelCallback_2_1(event, mCookie);
744 }
745 }
746
747 // Begin V2_2 implementation, copied from
748 // hardware/interfaces/soundtrigger/2.2/default/SoundTriggerHw.cpp
749
getModelState(int32_t modelHandle)750 Return<int32_t> SoundTriggerHw::getModelState(int32_t modelHandle) {
751 sp<SoundModelClient> client;
752 if (mHwDevice == NULL) {
753 return -ENODEV;
754 }
755
756 {
757 AutoMutex lock(mLock);
758 client = mClients.valueFor(modelHandle);
759 if (client == 0) {
760 return -ENOSYS;
761 }
762 }
763
764 return mHwDevice->get_model_state(mHwDevice, client->getHalHandle());
765 }
766
767 // Begin V2_3 implementation
768
getProperties_2_3(ISoundTriggerHw::getProperties_2_3_cb _hidl_cb)769 Return<void> SoundTriggerHw::getProperties_2_3(ISoundTriggerHw::getProperties_2_3_cb _hidl_cb) {
770 ALOGV("getProperties_2_3() mHwDevice %p", mHwDevice);
771 int ret = 0;
772 V2_3::Properties properties;
773 const struct sound_trigger_properties_header* header;
774
775 if (mHwDevice == NULL) {
776 ret = -ENODEV;
777 goto exit;
778 }
779
780 header = mHwDevice->get_properties_extended(mHwDevice);
781
782 convertPropertiesFromHal(&properties, header);
783
784 ALOGV("getProperties_2_3 implementor %s supportedModelArch %s",
785 properties.base.implementor.c_str(), properties.supportedModelArch.c_str());
786
787 exit:
788 _hidl_cb(ret, properties);
789 return Void();
790 }
791
startRecognition_2_3(int32_t modelHandle,const V2_3::RecognitionConfig & config)792 Return<int32_t> SoundTriggerHw::startRecognition_2_3(int32_t modelHandle,
793 const V2_3::RecognitionConfig& config) {
794 int32_t ret;
795 sp<SoundTriggerHw::SoundModelClient> client;
796 struct sound_trigger_recognition_config_header* header;
797
798 if (mHwDevice == NULL) {
799 ret = -ENODEV;
800 goto exit;
801 }
802
803 {
804 AutoMutex lock(mLock);
805 client = mClients.valueFor(modelHandle);
806 if (client == 0) {
807 ret = -ENOSYS;
808 goto exit;
809 }
810 }
811
812 header = convertRecognitionConfigToHalHeader(&config);
813
814 if (header == nullptr) {
815 ret = -EINVAL;
816 goto exit;
817 }
818 ret = mHwDevice->start_recognition_extended(mHwDevice, client->getHalHandle(), header,
819 recognitionCallback_, client.get());
820
821 free(header);
822
823 exit:
824 return ret;
825 }
826
setParameter(V2_0::SoundModelHandle modelHandle,ModelParameter modelParam,int32_t value)827 Return<int32_t> SoundTriggerHw::setParameter(V2_0::SoundModelHandle modelHandle,
828 ModelParameter modelParam, int32_t value) {
829 sp<SoundModelClient> client;
830 if (mHwDevice == NULL) {
831 return -ENODEV;
832 }
833
834 {
835 AutoMutex lock(mLock);
836 client = mClients.valueFor(modelHandle);
837 if (client == 0) {
838 return -EINVAL;
839 }
840 }
841
842 return mHwDevice->set_parameter(mHwDevice, client->getHalHandle(),
843 convertModelParameterToHal(modelParam), value);
844 }
845
getParameter(V2_0::SoundModelHandle modelHandle,ModelParameter modelParam,getParameter_cb _hidl_cb)846 Return<void> SoundTriggerHw::getParameter(V2_0::SoundModelHandle modelHandle,
847 ModelParameter modelParam, getParameter_cb _hidl_cb) {
848 sp<SoundModelClient> client;
849 if (mHwDevice == NULL) {
850 _hidl_cb(-ENODEV, 0);
851 return Void();
852 }
853
854 {
855 AutoMutex lock(mLock);
856 client = mClients.valueFor(modelHandle);
857 if (client == 0) {
858 _hidl_cb(-EINVAL, 0);
859 return Void();
860 }
861 }
862
863 int32_t value;
864 int32_t status = mHwDevice->get_parameter(mHwDevice, client->getHalHandle(),
865 convertModelParameterToHal(modelParam), &value);
866 _hidl_cb(status, value);
867 return Void();
868 }
869
queryParameter(V2_0::SoundModelHandle modelHandle,ModelParameter modelParam,queryParameter_cb _hidl_cb)870 Return<void> SoundTriggerHw::queryParameter(V2_0::SoundModelHandle modelHandle,
871 ModelParameter modelParam, queryParameter_cb _hidl_cb) {
872 OptionalModelParameterRange optionalParamRange;
873 sp<SoundModelClient> client;
874 if (mHwDevice == NULL) {
875 _hidl_cb(-ENODEV, optionalParamRange);
876 return Void();
877 }
878
879 {
880 AutoMutex lock(mLock);
881 client = mClients.valueFor(modelHandle);
882 if (client == 0) {
883 _hidl_cb(-EINVAL, optionalParamRange);
884 return Void();
885 }
886 }
887
888 sound_trigger_model_parameter_range_t paramRange;
889 int32_t status = mHwDevice->query_parameter(
890 mHwDevice, client->getHalHandle(), convertModelParameterToHal(modelParam), ¶mRange);
891
892 if (status == 0 && paramRange.is_supported) {
893 optionalParamRange.range({.start = paramRange.start, .end = paramRange.end});
894 }
895 _hidl_cb(status, optionalParamRange);
896 return Void();
897 }
898
899 // static
convertModelParameterToHal(ModelParameter param)900 sound_trigger_model_parameter_t SoundTriggerHw::convertModelParameterToHal(ModelParameter param) {
901 switch (param) {
902 case ModelParameter::THRESHOLD_FACTOR:
903 return MODEL_PARAMETER_THRESHOLD_FACTOR;
904 case ModelParameter::INVALID:
905 default:
906 return MODEL_PARAMETER_INVALID;
907 }
908 }
909
910 // Methods from ::android::hidl::base::V1_0::IBase follow.
911
HIDL_FETCH_ISoundTriggerHw(const char *)912 ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) {
913 return new SoundTriggerHw();
914 }
915
916 } // namespace implementation
917 } // namespace V2_3
918 } // namespace soundtrigger
919 } // namespace hardware
920 } // namespace android
921