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