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