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