blob: 73066e69e70c8b47f8b49d3f83d49d53d980dc88 [file] [log] [blame]
Eric Laurent27ef4d82016-10-14 15:46:06 -07001/*
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
Yifan Hongf9d30342016-11-30 13:45:34 -080020#include <android/log.h>
Eric Laurent27ef4d82016-10-14 15:46:06 -070021#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 %d", 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(const char *moduleName)
298 : mModuleName(moduleName), mNextModelId(1)
299{
300}
301
302void SoundTriggerHalImpl::onFirstRef()
303{
304 const hw_module_t *mod;
305 int rc;
306
307 if (mModuleName == NULL || strlen(mModuleName) == 0) {
308 mModuleName = "primary";
309 }
310 rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
311 if (rc != 0) {
312 ALOGE("couldn't load sound trigger module %s.%s (%s)",
313 SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
314 return;
315 }
316 rc = sound_trigger_hw_device_open(mod, &mHwDevice);
317 if (rc != 0) {
318 ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
319 SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
320 mHwDevice = NULL;
321 return;
322 }
323 if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
324 mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
325 ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
326 sound_trigger_hw_device_close(mHwDevice);
327 mHwDevice = NULL;
328 return;
329 }
330
331 ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
332}
333
334SoundTriggerHalImpl::~SoundTriggerHalImpl()
335{
336 if (mHwDevice != NULL) {
337 sound_trigger_hw_device_close(mHwDevice);
338 }
339}
340
341uint32_t SoundTriggerHalImpl::nextUniqueId()
342{
343 return (uint32_t) atomic_fetch_add_explicit(&mNextModelId,
344 (uint_fast32_t) 1, memory_order_acq_rel);
345}
346
347void SoundTriggerHalImpl::convertUuidFromHal(Uuid *uuid,
348 const sound_trigger_uuid_t *halUuid)
349{
350 uuid->timeLow = halUuid->timeLow;
351 uuid->timeMid = halUuid->timeMid;
352 uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
353 uuid->variantAndClockSeqHigh = halUuid->clockSeq;
354 memcpy(&uuid->node[0], &halUuid->node[0], 6);
355}
356
357void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t *halUuid,
358 const Uuid *uuid)
359{
360 halUuid->timeLow = uuid->timeLow;
361 halUuid->timeMid = uuid->timeMid;
362 halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
363 halUuid->clockSeq = uuid->variantAndClockSeqHigh;
364 memcpy(&halUuid->node[0], &uuid->node[0], 6);
365}
366
367void SoundTriggerHalImpl::convertPropertiesFromHal(
368 ISoundTriggerHw::Properties *properties,
369 const struct sound_trigger_properties *halProperties)
370{
371 properties->implementor = halProperties->implementor;
372 properties->description = halProperties->description;
373 properties->version = halProperties->version;
374 convertUuidFromHal(&properties->uuid, &halProperties->uuid);
375 properties->maxSoundModels = halProperties->max_sound_models;
376 properties->maxKeyPhrases = halProperties->max_key_phrases;
377 properties->maxUsers = halProperties->max_users;
378 properties->recognitionModes = halProperties->recognition_modes;
379 properties->captureTransition = halProperties->capture_transition;
380 properties->maxBufferMs = halProperties->max_buffer_ms;
381 properties->concurrentCapture = halProperties->concurrent_capture;
382 properties->triggerInEvent = halProperties->trigger_in_event;
383 properties->powerConsumptionMw = halProperties->power_consumption_mw;
384
385}
386
387void SoundTriggerHalImpl::convertTriggerPhraseToHal(
388 struct sound_trigger_phrase *halTriggerPhrase,
389 const ISoundTriggerHw::Phrase *triggerPhrase)
390{
391 halTriggerPhrase->id = triggerPhrase->id;
392 halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
393 unsigned int i;
394 for (i = 0; i < triggerPhrase->users.size(); i++) {
395 halTriggerPhrase->users[i] = triggerPhrase->users[i];
396 }
397 halTriggerPhrase->num_users = i;
398
399 strlcpy(halTriggerPhrase->locale,
400 triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
401 strlcpy(halTriggerPhrase->text,
402 triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
403}
404
405struct sound_trigger_sound_model *SoundTriggerHalImpl::convertSoundModelToHal(
406 const ISoundTriggerHw::SoundModel *soundModel)
407{
408 struct sound_trigger_sound_model *halModel = NULL;
409 if (soundModel->type == SoundModelType::KEYPHRASE) {
410 size_t allocSize =
411 sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
412 struct sound_trigger_phrase_sound_model *halKeyPhraseModel =
413 static_cast<struct sound_trigger_phrase_sound_model *>(malloc(allocSize));
414 LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
415 "malloc failed for size %zu in convertSoundModelToHal PHRASE", allocSize);
416
417 const ISoundTriggerHw::PhraseSoundModel *keyPhraseModel =
418 reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel *>(soundModel);
419
420 size_t i;
421 for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
422 convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i],
423 &keyPhraseModel->phrases[i]);
424 }
425 halKeyPhraseModel->num_phrases = (unsigned int)i;
426 halModel = reinterpret_cast<struct sound_trigger_sound_model *>(halKeyPhraseModel);
427 halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
428 } else {
429 size_t allocSize =
430 sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
431 halModel = static_cast<struct sound_trigger_sound_model *>(malloc(allocSize));
432 LOG_ALWAYS_FATAL_IF(halModel == NULL,
433 "malloc failed for size %zu in convertSoundModelToHal GENERIC",
434 allocSize);
435
436 halModel->data_offset = sizeof(struct sound_trigger_sound_model);
437 }
438 halModel->type = (sound_trigger_sound_model_type_t)soundModel->type;
439 convertUuidToHal(&halModel->uuid, &soundModel->uuid);
440 convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
441 halModel->data_size = soundModel->data.size();
442 uint8_t *dst = reinterpret_cast<uint8_t *>(halModel) + halModel->data_offset;
443 const uint8_t *src = reinterpret_cast<const uint8_t *>(&soundModel->data[0]);
444 memcpy(dst, src, soundModel->data.size());
445
446 return halModel;
447}
448
449void SoundTriggerHalImpl::convertPhraseRecognitionExtraToHal(
450 struct sound_trigger_phrase_recognition_extra *halExtra,
451 const PhraseRecognitionExtra *extra)
452{
453 halExtra->id = extra->id;
454 halExtra->recognition_modes = extra->recognitionModes;
455 halExtra->confidence_level = extra->confidenceLevel;
456
457 unsigned int i;
458 for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
459 halExtra->levels[i].user_id = extra->levels[i].userId;
460 halExtra->levels[i].level = extra->levels[i].levelPercent;
461 }
462 halExtra->num_levels = i;
463}
464
465struct sound_trigger_recognition_config *SoundTriggerHalImpl::convertRecognitionConfigToHal(
466 const ISoundTriggerHw::RecognitionConfig *config)
467{
468 size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
469 struct sound_trigger_recognition_config *halConfig =
470 static_cast<struct sound_trigger_recognition_config *>(malloc(allocSize));
471
472 LOG_ALWAYS_FATAL_IF(halConfig == NULL,
473 "malloc failed for size %zu in convertRecognitionConfigToHal",
474 allocSize);
475
476 halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
477 halConfig->capture_device = (audio_devices_t)config->captureDevice;
478 halConfig->capture_requested = config->captureRequested;
479
480 unsigned int i;
481 for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
482 convertPhraseRecognitionExtraToHal(&halConfig->phrases[i],
483 &config->phrases[i]);
484 }
485 halConfig->num_phrases = i;
486
487 halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
488 halConfig->data_size = config->data.size();
489 uint8_t *dst = reinterpret_cast<uint8_t *>(halConfig) + halConfig->data_offset;
490 const uint8_t *src = reinterpret_cast<const uint8_t *>(&config->data[0]);
491 memcpy(dst, src, config->data.size());
492 return halConfig;
493}
494
495// static
496void SoundTriggerHalImpl::convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
497 const struct sound_trigger_model_event *halEvent)
498{
499 event->status = (ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
500 // event->model to be remapped by called
501 event->data.setToExternal(
502 const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
503 halEvent->data_size);
504}
505
506// static
507ISoundTriggerHwCallback::RecognitionEvent *SoundTriggerHalImpl::convertRecognitionEventFromHal(
508 const struct sound_trigger_recognition_event *halEvent)
509{
510 ISoundTriggerHwCallback::RecognitionEvent * event;
511
512 if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
513 const struct sound_trigger_phrase_recognition_event *halPhraseEvent =
514 reinterpret_cast<const struct sound_trigger_phrase_recognition_event *>(halEvent);
515 ISoundTriggerHwCallback::PhraseRecognitionEvent *phraseEvent =
516 new ISoundTriggerHwCallback::PhraseRecognitionEvent();
517
518 PhraseRecognitionExtra *phraseExtras =
519 new PhraseRecognitionExtra[halPhraseEvent->num_phrases];
520 for (unsigned int i = 0; i < halPhraseEvent->num_phrases; i++) {
521 convertPhraseRecognitionExtraFromHal(&phraseExtras[i],
522 &halPhraseEvent->phrase_extras[i]);
523 }
524 phraseEvent->phraseExtras.setToExternal(phraseExtras, halPhraseEvent->num_phrases);
525 // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
526 phraseEvent->phraseExtras.resize(halPhraseEvent->num_phrases);
527 delete[] phraseExtras;
528 event = reinterpret_cast<ISoundTriggerHwCallback::RecognitionEvent *>(phraseEvent);
529 } else {
530 event = new ISoundTriggerHwCallback::RecognitionEvent();
531 }
532
533 event->status = static_cast<ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
534 event->type = static_cast<SoundModelType>(halEvent->type);
535 // event->model to be remapped by called
536 event->captureAvailable = halEvent->capture_available;
537 event->captureSession = halEvent->capture_session;
538 event->captureDelayMs = halEvent->capture_delay_ms;
539 event->capturePreambleMs = halEvent->capture_preamble_ms;
540 event->triggerInData = halEvent->trigger_in_data;
541 event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
542 event->audioConfig.channelMask =
543 (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
544 event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
545 event->data.setToExternal(
546 const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
547 halEvent->data_size);
548
549 return event;
550}
551
552// static
553void SoundTriggerHalImpl::convertPhraseRecognitionExtraFromHal(
554 PhraseRecognitionExtra *extra,
555 const struct sound_trigger_phrase_recognition_extra *halExtra)
556{
557 extra->id = halExtra->id;
558 extra->recognitionModes = halExtra->recognition_modes;
559 extra->confidenceLevel = halExtra->confidence_level;
560
561 ConfidenceLevel *levels =
562 new ConfidenceLevel[halExtra->num_levels];
563 for (unsigned int i = 0; i < halExtra->num_levels; i++) {
564 levels[i].userId = halExtra->levels[i].user_id;
565 levels[i].levelPercent = halExtra->levels[i].level;
566 }
567 extra->levels.setToExternal(levels, halExtra->num_levels);
568 // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
569 extra->levels.resize(halExtra->num_levels);
570 delete[] levels;
571}
572
573ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name)
574{
575 if (name != NULL) {
576 if (strncmp(SOUND_TRIGGER_HARDWARE_MODULE_ID, name,
577 strlen(SOUND_TRIGGER_HARDWARE_MODULE_ID)) != 0) {
578 return NULL;
579 }
580 name = strchr(name, '.');
581 if (name == NULL) {
582 return NULL;
583 }
584 name++;
585 }
586 return new SoundTriggerHalImpl(name);
587}
588} // namespace implementation
589} // namespace V2_0
590} // namespace soundtrigger
591} // namespace hardware
592} // namespace android
593
594
595