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