• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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