SoundTriggerHalHidl.cpp revision f7854d45bd12d5239c588767bf85953aca46b4ef
1/*
2 * Copyright (C) 2016 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 "SoundTriggerHalHidl"
18//#define LOG_NDEBUG 0
19
20#include <utils/Log.h>
21#include "SoundTriggerHalHidl.h"
22#include <hidl/IServiceManager.h>
23#include <hwbinder/IPCThreadState.h>
24#include <hwbinder/ProcessState.h>
25
26namespace android {
27
28using android::hardware::Return;
29using android::hardware::ProcessState;
30using android::hardware::audio::common::V2_0::AudioDevice;
31
32pthread_once_t SoundTriggerHalHidl::sOnceControl = PTHREAD_ONCE_INIT;
33
34void SoundTriggerHalHidl::sOnceInit()
35{
36    ProcessState::self()->setThreadPoolMaxThreadCount(1);
37    ProcessState::self()->startThreadPool();
38}
39
40/* static */
41sp<SoundTriggerHalInterface> SoundTriggerHalInterface::connectModule(const char *moduleName)
42{
43    return new SoundTriggerHalHidl(moduleName);
44}
45
46int SoundTriggerHalHidl::getProperties(struct sound_trigger_properties *properties)
47{
48    sp<ISoundTriggerHw> soundtrigger = getService();
49    if (soundtrigger == 0) {
50        return -ENODEV;
51    }
52
53    ISoundTriggerHw::Properties halProperties;
54    Return<void> hidlReturn;
55    int32_t halReturn;
56    {
57        AutoMutex lock(mHalLock);
58        hidlReturn = soundtrigger->getProperties([&](int rc, auto res) {
59            halReturn = rc;
60            halProperties = res;
61            ALOGI("getProperties res implementor %s", res.implementor.c_str());
62        });
63    }
64
65    int ret = 0;
66    if (hidlReturn.getStatus().isOk()) {
67        convertPropertiesFromHal(properties, &halProperties);
68    } else {
69        ret = (int)hidlReturn.getStatus().transactionError();
70        if (ret == -EPIPE) {
71            clearService();
72        }
73    }
74
75    return ret;
76}
77
78int SoundTriggerHalHidl::loadSoundModel(struct sound_trigger_sound_model *sound_model,
79                        sound_model_callback_t callback,
80                        void *cookie,
81                        sound_model_handle_t *handle)
82{
83    if (handle == NULL) {
84        return -EINVAL;
85    }
86
87    sp<ISoundTriggerHw> soundtrigger = getService();
88    if (soundtrigger == 0) {
89        return -ENODEV;
90    }
91
92    uint32_t modelId;
93    {
94        AutoMutex lock(mLock);
95        do {
96            modelId = nextUniqueId();
97            ALOGI("loadSoundModel modelId %u", modelId);
98            sp<SoundModel> model = mSoundModels.valueFor(modelId);
99            ALOGI("loadSoundModel model %p", model.get());
100        } while (mSoundModels.valueFor(modelId) != 0 && modelId != 0);
101    }
102    LOG_ALWAYS_FATAL_IF(modelId == 0,
103                        "loadSoundModel(): wrap around in sound model IDs, num loaded models %zd",
104                        mSoundModels.size());
105
106    ISoundTriggerHw::SoundModel *halSoundModel =
107            convertSoundModelToHal(sound_model);
108    if (halSoundModel == NULL) {
109        return -EINVAL;
110    }
111
112    Return<void> hidlReturn;
113    int32_t halReturn;
114    SoundModelHandle halHandle;
115    {
116        AutoMutex lock(mHalLock);
117        if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
118            hidlReturn = soundtrigger->loadPhraseSoundModel(
119                    *(const ISoundTriggerHw::PhraseSoundModel *)halSoundModel,
120                    this, modelId, [&](int32_t retval, auto res) {
121                halReturn = retval;
122                halHandle = res;
123            });
124
125        } else {
126            hidlReturn = soundtrigger->loadSoundModel(*halSoundModel,
127                    this, modelId, [&](int32_t retval, auto res) {
128                halReturn = retval;
129                halHandle = res;
130            });
131        }
132    }
133
134    delete halSoundModel;
135
136    int ret = 0;
137    if (hidlReturn.getStatus().isOk()) {
138        AutoMutex lock(mLock);
139        *handle = (sound_model_handle_t)modelId;
140        sp<SoundModel> model = new SoundModel(*handle, callback, cookie, halHandle);
141        mSoundModels.add(*handle, model);
142    } else {
143        ret = (int)hidlReturn.getStatus().transactionError();
144        ALOGE("loadSoundModel error %d", ret);
145        if (ret == -EPIPE) {
146            clearService();
147        }
148    }
149
150
151    return ret;
152}
153
154int SoundTriggerHalHidl::unloadSoundModel(sound_model_handle_t handle)
155{
156    sp<ISoundTriggerHw> soundtrigger = getService();
157    if (soundtrigger == 0) {
158        return -ENODEV;
159    }
160
161    sp<SoundModel> model = removeModel(handle);
162    if (model == 0) {
163        ALOGE("unloadSoundModel model not found for handle %u", handle);
164        return -EINVAL;
165    }
166
167    Return<int32_t> halReturn(0);
168    {
169        AutoMutex lock(mHalLock);
170        halReturn = soundtrigger->unloadSoundModel(model->mHalHandle);
171    }
172
173    int ret = (int)halReturn.getStatus().transactionError();
174    ALOGE_IF(ret != 0, "unloadSoundModel error %d", ret);
175    if (ret == -EPIPE) {
176        clearService();
177    }
178
179    return ret;
180}
181
182int SoundTriggerHalHidl::startRecognition(sound_model_handle_t handle,
183                         const struct sound_trigger_recognition_config *config,
184                         recognition_callback_t callback,
185                         void *cookie)
186{
187    sp<ISoundTriggerHw> soundtrigger = getService();
188    if (soundtrigger == 0) {
189        return -ENODEV;
190    }
191
192    sp<SoundModel> model = getModel(handle);
193    if (model == 0) {
194        ALOGE("startRecognition model not found for handle %u", handle);
195        return -EINVAL;
196    }
197
198    model->mRecognitionCallback = callback;
199    model->mRecognitionCookie = cookie;
200
201    ISoundTriggerHw::RecognitionConfig *halConfig =
202            convertRecognitionConfigToHal(config);
203
204    Return<int32_t> halReturn(0);
205    {
206        AutoMutex lock(mHalLock);
207        halReturn = soundtrigger->startRecognition(model->mHalHandle, *halConfig, this, handle);
208    }
209
210    delete halConfig;
211
212    int ret = (int)halReturn.getStatus().transactionError();
213    ALOGE_IF(ret != 0, "startRecognition error %d", ret);
214    if (ret == -EPIPE) {
215        clearService();
216    }
217    return ret;
218}
219
220int SoundTriggerHalHidl::stopRecognition(sound_model_handle_t handle)
221{
222    sp<ISoundTriggerHw> soundtrigger = getService();
223    if (soundtrigger == 0) {
224        return -ENODEV;
225    }
226
227    sp<SoundModel> model = getModel(handle);
228    if (model == 0) {
229        ALOGE("stopRecognition model not found for handle %u", handle);
230        return -EINVAL;
231    }
232
233    Return<int32_t> halReturn(0);
234    {
235        AutoMutex lock(mHalLock);
236        halReturn = soundtrigger->stopRecognition(model->mHalHandle);
237    }
238
239    int ret = (int)halReturn.getStatus().transactionError();
240    ALOGE_IF(ret != 0, "stopRecognition error %d", ret);
241    if (ret == -EPIPE) {
242        clearService();
243    }
244    return ret;
245}
246
247int SoundTriggerHalHidl::stopAllRecognitions()
248{
249    sp<ISoundTriggerHw> soundtrigger = getService();
250    if (soundtrigger == 0) {
251        return -ENODEV;
252    }
253
254    Return<int32_t> halReturn(0);
255    {
256        AutoMutex lock(mHalLock);
257        Return<int32_t> halReturn = soundtrigger->stopAllRecognitions();
258    }
259
260    int ret = (int)halReturn.getStatus().transactionError();
261    ALOGE_IF(ret != 0, "stopAllRecognitions error %d", ret);
262    if (ret == -EPIPE) {
263        clearService();
264    }
265    return ret;
266}
267
268SoundTriggerHalHidl::SoundTriggerHalHidl(const char *moduleName)
269    : mModuleName(moduleName), mNextUniqueId(1)
270{
271}
272
273void SoundTriggerHalHidl::onFirstRef()
274{
275    pthread_once(&sOnceControl, &sOnceInit);
276}
277
278SoundTriggerHalHidl::~SoundTriggerHalHidl()
279{
280}
281
282sp<ISoundTriggerHw> SoundTriggerHalHidl::getService()
283{
284    AutoMutex lock(mLock);
285    if (mISoundTrigger == 0) {
286        if (mModuleName == NULL) {
287            mModuleName = "primary";
288        }
289        std::string serviceName = "sound_trigger.";
290        serviceName.append(mModuleName);
291        mISoundTrigger = ISoundTriggerHw::getService(serviceName);
292    }
293    return mISoundTrigger;
294}
295
296void SoundTriggerHalHidl::clearService()
297{
298    AutoMutex lock(mLock);
299    mISoundTrigger = 0;
300}
301
302sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
303{
304    AutoMutex lock(mLock);
305    return mSoundModels.valueFor(handle);
306}
307
308sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::removeModel(sound_model_handle_t handle)
309{
310    AutoMutex lock(mLock);
311    sp<SoundModel> model = mSoundModels.valueFor(handle);
312    mSoundModels.removeItem(handle);
313    return model;
314}
315
316uint32_t SoundTriggerHalHidl::nextUniqueId()
317{
318    return (uint32_t) atomic_fetch_add_explicit(&mNextUniqueId,
319                (uint_fast32_t) 1, memory_order_acq_rel);
320}
321
322void SoundTriggerHalHidl::convertUuidToHal(Uuid *halUuid,
323                                           const sound_trigger_uuid_t *uuid)
324{
325    halUuid->timeLow = uuid->timeLow;
326    halUuid->timeMid = uuid->timeMid;
327    halUuid->versionAndTimeHigh = uuid->timeHiAndVersion;
328    halUuid->variantAndClockSeqHigh = uuid->clockSeq;
329    memcpy(halUuid->node.data(), &uuid->node[0], sizeof(uuid->node));
330}
331
332void SoundTriggerHalHidl::convertUuidFromHal(sound_trigger_uuid_t *uuid,
333                                             const Uuid *halUuid)
334{
335    uuid->timeLow = halUuid->timeLow;
336    uuid->timeMid = halUuid->timeMid;
337    uuid->timeHiAndVersion = halUuid->versionAndTimeHigh;
338    uuid->clockSeq = halUuid->variantAndClockSeqHigh;
339    memcpy(&uuid->node[0], halUuid->node.data(), sizeof(uuid->node));
340}
341
342void SoundTriggerHalHidl::convertPropertiesFromHal(
343        struct sound_trigger_properties *properties,
344        const ISoundTriggerHw::Properties *halProperties)
345{
346    strlcpy(properties->implementor,
347            halProperties->implementor.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
348    strlcpy(properties->description,
349            halProperties->description.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
350    properties->version = halProperties->version;
351    convertUuidFromHal(&properties->uuid, &halProperties->uuid);
352    properties->max_sound_models = halProperties->maxSoundModels;
353    properties->max_key_phrases = halProperties->maxKeyPhrases;
354    properties->max_users = halProperties->maxUsers;
355    properties->recognition_modes = halProperties->recognitionModes;
356    properties->capture_transition = (bool)halProperties->captureTransition;
357    properties->max_buffer_ms = halProperties->maxBufferMs;
358    properties->concurrent_capture = (bool)halProperties->concurrentCapture;
359    properties->trigger_in_event = (bool)halProperties->triggerInEvent;
360    properties->power_consumption_mw = halProperties->powerConsumptionMw;
361}
362
363void SoundTriggerHalHidl::convertTriggerPhraseToHal(
364        ISoundTriggerHw::Phrase *halTriggerPhrase,
365        const struct sound_trigger_phrase *triggerPhrase)
366{
367    halTriggerPhrase->id = triggerPhrase->id;
368    halTriggerPhrase->recognitionModes = triggerPhrase->recognition_mode;
369    halTriggerPhrase->users.setToExternal((uint32_t *)&triggerPhrase->users[0], triggerPhrase->num_users);
370    halTriggerPhrase->locale = triggerPhrase->locale;
371    halTriggerPhrase->text = triggerPhrase->text;
372}
373
374ISoundTriggerHw::SoundModel *SoundTriggerHalHidl::convertSoundModelToHal(
375        const struct sound_trigger_sound_model *soundModel)
376{
377    ISoundTriggerHw::SoundModel *halModel = NULL;
378    if (soundModel->type == SOUND_MODEL_TYPE_KEYPHRASE) {
379        ISoundTriggerHw::PhraseSoundModel *halKeyPhraseModel =
380                new ISoundTriggerHw::PhraseSoundModel();
381        struct sound_trigger_phrase_sound_model *keyPhraseModel =
382                (struct sound_trigger_phrase_sound_model *)soundModel;
383        ISoundTriggerHw::Phrase *halPhrases =
384                new ISoundTriggerHw::Phrase[keyPhraseModel->num_phrases];
385
386
387        for (unsigned int i = 0; i < keyPhraseModel->num_phrases; i++) {
388            convertTriggerPhraseToHal(&halPhrases[i],
389                                      &keyPhraseModel->phrases[i]);
390        }
391        halKeyPhraseModel->phrases.setToExternal(halPhrases, keyPhraseModel->num_phrases);
392        // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
393        halKeyPhraseModel->phrases.resize(keyPhraseModel->num_phrases);
394
395        delete[] halPhrases;
396
397        halModel = (ISoundTriggerHw::SoundModel *)halKeyPhraseModel;
398    } else {
399        halModel = new ISoundTriggerHw::SoundModel();
400    }
401    halModel->type = (SoundModelType)soundModel->type;
402    convertUuidToHal(&halModel->uuid, &soundModel->uuid);
403    convertUuidToHal(&halModel->vendorUuid, &soundModel->vendor_uuid);
404    halModel->data.setToExternal((uint8_t *)soundModel + soundModel->data_offset, soundModel->data_size);
405    halModel->data.resize(soundModel->data_size);
406
407    return halModel;
408}
409
410void SoundTriggerHalHidl::convertPhraseRecognitionExtraToHal(
411        PhraseRecognitionExtra *halExtra,
412        const struct sound_trigger_phrase_recognition_extra *extra)
413{
414    halExtra->id = extra->id;
415    halExtra->recognitionModes = extra->recognition_modes;
416    halExtra->confidenceLevel = extra->confidence_level;
417    ConfidenceLevel *halLevels =
418            new ConfidenceLevel[extra->num_levels];
419    for (unsigned int i = 0; i < extra->num_levels; i++) {
420        halLevels[i].userId = extra->levels[i].user_id;
421        halLevels[i].levelPercent = extra->levels[i].level;
422    }
423    halExtra->levels.setToExternal(halLevels, extra->num_levels);
424    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
425    halExtra->levels.resize(extra->num_levels);
426
427    delete[] halLevels;
428}
429
430
431ISoundTriggerHw::RecognitionConfig *SoundTriggerHalHidl::convertRecognitionConfigToHal(
432        const struct sound_trigger_recognition_config *config)
433{
434    ISoundTriggerHw::RecognitionConfig *halConfig =
435            new ISoundTriggerHw::RecognitionConfig();
436
437    halConfig->captureHandle = config->capture_handle;
438    halConfig->captureDevice = (AudioDevice)config->capture_device;
439    halConfig->captureRequested = (uint32_t)config->capture_requested;
440
441    PhraseRecognitionExtra *halExtras =
442            new PhraseRecognitionExtra[config->num_phrases];
443
444    for (unsigned int i = 0; i < config->num_phrases; i++) {
445        convertPhraseRecognitionExtraToHal(&halExtras[i],
446                                  &config->phrases[i]);
447    }
448    halConfig->phrases.setToExternal(halExtras, config->num_phrases);
449    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
450    halConfig->phrases.resize(config->num_phrases);
451
452    delete[] halExtras;
453
454    halConfig->data.setToExternal((uint8_t *)config + config->data_offset, config->data_size);
455
456    return halConfig;
457}
458
459
460// ISoundTriggerHwCallback
461::android::hardware::Return<void> SoundTriggerHalHidl::recognitionCallback(
462        const ISoundTriggerHwCallback::RecognitionEvent& halEvent,
463        CallbackCookie cookie)
464{
465    sp<SoundModel> model;
466    {
467        AutoMutex lock(mLock);
468        model = mSoundModels.valueFor((SoundModelHandle)cookie);
469        if (model == 0) {
470            return Return<void>();
471        }
472    }
473    struct sound_trigger_recognition_event *event = convertRecognitionEventFromHal(&halEvent);
474    if (event == NULL) {
475        return Return<void>();
476    }
477    event->model = model->mHandle;
478    model->mRecognitionCallback(event, model->mRecognitionCookie);
479
480    free(event);
481
482    return Return<void>();
483}
484
485::android::hardware::Return<void> SoundTriggerHalHidl::phraseRecognitionCallback(
486        const ISoundTriggerHwCallback::PhraseRecognitionEvent& halEvent,
487        CallbackCookie cookie)
488{
489    sp<SoundModel> model;
490    {
491        AutoMutex lock(mLock);
492        model = mSoundModels.valueFor((SoundModelHandle)cookie);
493        if (model == 0) {
494            return Return<void>();
495        }
496    }
497
498    struct sound_trigger_recognition_event *event = convertRecognitionEventFromHal(
499                                   (const ISoundTriggerHwCallback::RecognitionEvent *)&halEvent);
500    if (event == NULL) {
501        return Return<void>();
502    }
503
504    event->model = model->mHandle;
505    model->mRecognitionCallback(event, model->mRecognitionCookie);
506
507    free(event);
508
509    return Return<void>();
510}
511
512::android::hardware::Return<void> SoundTriggerHalHidl::soundModelCallback(
513        const ISoundTriggerHwCallback::ModelEvent& halEvent,
514        CallbackCookie cookie)
515{
516    sp<SoundModel> model;
517    {
518        AutoMutex lock(mLock);
519        model = mSoundModels.valueFor((SoundModelHandle)cookie);
520        if (model == 0) {
521            return Return<void>();
522        }
523    }
524
525    struct sound_trigger_model_event *event = convertSoundModelEventFromHal(&halEvent);
526    if (event == NULL) {
527        return Return<void>();
528    }
529
530    event->model = model->mHandle;
531    model->mSoundModelCallback(event, model->mSoundModelCookie);
532
533    free(event);
534
535    return Return<void>();
536}
537
538
539struct sound_trigger_model_event *SoundTriggerHalHidl::convertSoundModelEventFromHal(
540                                              const ISoundTriggerHwCallback::ModelEvent *halEvent)
541{
542    struct sound_trigger_model_event *event = (struct sound_trigger_model_event *)malloc(
543            sizeof(struct sound_trigger_model_event) +
544            halEvent->data.size());
545    if (event == NULL) {
546        return NULL;
547    }
548
549    event->status = (int)halEvent->status;
550    // event->model to be set by caller
551    event->data_offset = sizeof(struct sound_trigger_model_event);
552    event->data_size = halEvent->data.size();
553    uint8_t *dst = (uint8_t *)event + event->data_offset;
554    uint8_t *src = (uint8_t *)&halEvent->data[0];
555    memcpy(dst, src, halEvent->data.size());
556
557    return event;
558}
559
560void SoundTriggerHalHidl::convertPhraseRecognitionExtraFromHal(
561        struct sound_trigger_phrase_recognition_extra *extra,
562        const PhraseRecognitionExtra *halExtra)
563{
564    extra->id = halExtra->id;
565    extra->recognition_modes = halExtra->recognitionModes;
566    extra->confidence_level = halExtra->confidenceLevel;
567
568    size_t i;
569    for (i = 0; i < halExtra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
570        extra->levels[i].user_id = halExtra->levels[i].userId;
571        extra->levels[i].level = halExtra->levels[i].levelPercent;
572    }
573    extra->num_levels = (unsigned int)i;
574}
575
576
577struct sound_trigger_recognition_event *SoundTriggerHalHidl::convertRecognitionEventFromHal(
578        const ISoundTriggerHwCallback::RecognitionEvent *halEvent)
579{
580    struct sound_trigger_recognition_event *event;
581
582    if (halEvent->type == SoundModelType::KEYPHRASE) {
583        struct sound_trigger_phrase_recognition_event *phraseEvent =
584                (struct sound_trigger_phrase_recognition_event *)malloc(
585                        sizeof(struct sound_trigger_phrase_recognition_event) +
586                        halEvent->data.size());
587        if (phraseEvent == NULL) {
588            return NULL;
589        }
590        const ISoundTriggerHwCallback::PhraseRecognitionEvent *halPhraseEvent =
591                (const ISoundTriggerHwCallback::PhraseRecognitionEvent *)halEvent;
592
593        for (unsigned int i = 0; i < halPhraseEvent->phraseExtras.size(); i++) {
594            convertPhraseRecognitionExtraFromHal(&phraseEvent->phrase_extras[i],
595                                                 &halPhraseEvent->phraseExtras[i]);
596        }
597        phraseEvent->num_phrases = halPhraseEvent->phraseExtras.size();
598        event = (struct sound_trigger_recognition_event *)phraseEvent;
599        event->data_offset = sizeof(sound_trigger_phrase_recognition_event);
600    } else {
601        event = (struct sound_trigger_recognition_event *)malloc(
602                sizeof(struct sound_trigger_recognition_event) + halEvent->data.size());
603        if (event == NULL) {
604            return NULL;
605        }
606        event->data_offset = sizeof(sound_trigger_recognition_event);
607    }
608    event->status = (int)halEvent->status;
609    event->type = (sound_trigger_sound_model_type_t)halEvent->type;
610    // event->model to be set by caller
611    event->capture_available = (bool)halEvent->captureAvailable;
612    event->capture_session = halEvent->captureSession;
613    event->capture_delay_ms = halEvent->captureDelayMs;
614    event->capture_preamble_ms = halEvent->capturePreambleMs;
615    event->trigger_in_data = (bool)halEvent->triggerInData;
616    event->audio_config.sample_rate = halEvent->audioConfig.sampleRateHz;
617    event->audio_config.channel_mask = (audio_channel_mask_t)halEvent->audioConfig.channelMask;
618    event->audio_config.format = (audio_format_t)halEvent->audioConfig.format;
619
620    event->data_size = halEvent->data.size();
621    uint8_t *dst = (uint8_t *)event + event->data_offset;
622    uint8_t *src = (uint8_t *)&halEvent->data[0];
623    memcpy(dst, src, halEvent->data.size());
624
625    return event;
626}
627
628} // namespace android
629