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