diff options
author | Nicholas Ambur <nambur@google.com> | 2019-10-01 13:11:26 -0700 |
---|---|---|
committer | Nicholas Ambur <nambur@google.com> | 2019-12-11 19:42:51 -0800 |
commit | 1e90019220b5ba78f573c00636a8650410d4e358 (patch) | |
tree | 7071f3f6bd0c57656a8b511ff5a9eac12db3b970 /soundtrigger | |
parent | d851ddf3e7877252cb4cbbc8acd4998229e46ff4 (diff) | |
download | platform_hardware_interfaces-1e90019220b5ba78f573c00636a8650410d4e358.tar.gz platform_hardware_interfaces-1e90019220b5ba78f573c00636a8650410d4e358.tar.bz2 platform_hardware_interfaces-1e90019220b5ba78f573c00636a8650410d4e358.zip |
add SoundTrigger HAL V2.3
add support for model parameter control APIs with THRESHOLD_FACTOR
as the first supported parameter
Bug: 141929369
Test: Tested manually with test app, GTS test
gts-tradefed run gts-dev -m GtsAssistIntentTestCases
and VTS test
vts-tradefed run vts-hal -m VtsHalSoundtriggerV2_3Target
Change-Id: I79d2b6365cc63fbdfe06fa94f1d0878903cbf554
Diffstat (limited to 'soundtrigger')
-rw-r--r-- | soundtrigger/2.3/Android.bp | 22 | ||||
-rw-r--r-- | soundtrigger/2.3/ISoundTriggerHw.hal | 87 | ||||
-rw-r--r-- | soundtrigger/2.3/default/Android.bp | 37 | ||||
-rw-r--r-- | soundtrigger/2.3/default/SoundTriggerHw.cpp | 804 | ||||
-rw-r--r-- | soundtrigger/2.3/default/SoundTriggerHw.h | 207 | ||||
-rw-r--r-- | soundtrigger/2.3/types.hal | 61 | ||||
-rw-r--r-- | soundtrigger/2.3/vts/functional/Android.bp | 31 | ||||
-rw-r--r-- | soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp | 59 |
8 files changed, 1308 insertions, 0 deletions
diff --git a/soundtrigger/2.3/Android.bp b/soundtrigger/2.3/Android.bp new file mode 100644 index 0000000000..3253a86695 --- /dev/null +++ b/soundtrigger/2.3/Android.bp @@ -0,0 +1,22 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.soundtrigger@2.3", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "ISoundTriggerHw.hal", + ], + interfaces: [ + "android.hardware.audio.common@2.0", + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", + ], + gen_java: true, +} diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal new file mode 100644 index 0000000000..207b9b74f9 --- /dev/null +++ b/soundtrigger/2.3/ISoundTriggerHw.hal @@ -0,0 +1,87 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.soundtrigger@2.3; + +import @2.0::SoundModelHandle; +import @2.2::ISoundTriggerHw; + +/** + * SoundTrigger HAL interface. Used for hardware recognition of hotwords + * and other sounds. + */ +interface ISoundTriggerHw extends @2.2::ISoundTriggerHw { + + /** + * Set a model specific parameter with the given value. This parameter + * will keep its value for the duration the model is loaded regardless of starting and stopping + * recognition. Once the model is unloaded, the value will be lost. + * It is expected to check if the handle supports the parameter via the queryParameter + * API prior to calling this method. + * + * @param modelHandle The sound model handle indicating which model to modify parameters + * @param modelParam Parameter to set which will be validated against the + * ModelParameter type. Not putting ModelParameter type + * directly in the definition and validating internally + * allows for forward compatibility. + * @param value The value to set for the given model parameter + * @return status Operation completion status: 0 in case of success, + * -ENODEV if the native service cannot be reached + * -EINVAL invalid input parameter + */ + setParameter(SoundModelHandle modelHandle, ModelParameter modelParam, int32_t value) + generates (int32_t status); + + /** + * Get a model specific parameter. This parameter will keep its value + * for the duration the model is loaded regardless of starting and stopping recognition. + * Once the model is unloaded, the value will be lost. If the value is not set, a default + * value is returned. See ModelParameter for parameter default values. + * It is expected to check if the handle supports the parameter via the queryParameter + * API prior to calling this method. + * + * @param modelHandle The sound model associated with given modelParam + * @param modelParam Parameter to set which will be validated against the + * ModelParameter type. Not putting ModelParameter type + * directly in the definition and validating internally + * allows for forward compatibility. + * @return status Operation completion status: 0 in case of success, + * -ENODEV if the native service cannot be reached + * -EINVAL invalid input parameter + * @return value Value set to the requested parameter. Value is only set when status + * indicates success. + */ + getParameter(SoundModelHandle modelHandle, ModelParameter modelParam) + generates (int32_t status, int32_t value); + + /** + * Get supported parameter attributes with respect to the provided model + * handle. Along with determining the valid range, this API is also used + * to determine if a given parameter ID is supported at all by the + * modelHandle for use with getParameter and setParameter APIs. + * + * @param modelHandle The sound model handle indicating which model to query + * @param modelParam Parameter to set which will be validated against the + * ModelParameter type + * @return status Operation completion status: 0 in case of success + * -ENODEV if the native service cannot be reached + * -EINVAL invalid input parameter + * @return retval ModelParameter structure indicating supported attributes + * of the parameter for the given model handle + */ + queryParameter(SoundModelHandle modelHandle, ModelParameter modelParam) + generates (int32_t status, OptionalModelParameterRange retval); +}; diff --git a/soundtrigger/2.3/default/Android.bp b/soundtrigger/2.3/default/Android.bp new file mode 100644 index 0000000000..be2c8b0961 --- /dev/null +++ b/soundtrigger/2.3/default/Android.bp @@ -0,0 +1,37 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_shared { + name: "android.hardware.soundtrigger@2.3-impl", + relative_install_path: "hw", + vendor: true, + srcs: [ + "SoundTriggerHw.cpp", + ], + shared_libs: [ + "libhidlbase", + "liblog", + "libhidlmemory", + "libutils", + "libhardware", + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.0-core", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hardware.soundtrigger@2.3", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + ], +} diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp new file mode 100644 index 0000000000..4a39ab562d --- /dev/null +++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp @@ -0,0 +1,804 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SoundTriggerHw" + +#include "SoundTriggerHw.h" + +#include <android/hidl/allocator/1.0/IAllocator.h> +#include <android/log.h> +#include <hidlmemory/mapping.h> +#include <utility> + +using android::hardware::hidl_memory; +using android::hidl::allocator::V1_0::IAllocator; +using android::hidl::memory::V1_0::IMemory; + +namespace android { +namespace hardware { +namespace soundtrigger { +namespace V2_3 { +namespace implementation { + +/** + * According to the HIDL C++ Users Guide: client and server implementations + * should never directly refer to anything other than the interface header + * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so + * this V2_3 implementation copies the previous implementations and + * then adds the new implementation. + */ + +// Begin V2_0 implementation, copied from +// hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp + +// static +void soundModelCallback_(struct sound_trigger_model_event* halEvent, void* cookie) { + if (halEvent == NULL) { + ALOGW("soundModelCallback called with NULL event"); + return; + } + sp<SoundTriggerHw::SoundModelClient> client = + wp<SoundTriggerHw::SoundModelClient>( + static_cast<SoundTriggerHw::SoundModelClient*>(cookie)) + .promote(); + if (client == 0) { + ALOGW("soundModelCallback called on stale client"); + return; + } + if (halEvent->model != client->getHalHandle()) { + ALOGW("soundModelCallback call with wrong handle %d on client with handle %d", + (int)halEvent->model, (int)client->getHalHandle()); + return; + } + + client->soundModelCallback(halEvent); +} + +// static +void recognitionCallback_(struct sound_trigger_recognition_event* halEvent, void* cookie) { + if (halEvent == NULL) { + ALOGW("recognitionCallback call NULL event"); + return; + } + sp<SoundTriggerHw::SoundModelClient> client = + wp<SoundTriggerHw::SoundModelClient>( + static_cast<SoundTriggerHw::SoundModelClient*>(cookie)) + .promote(); + if (client == 0) { + ALOGW("recognitionCallback called on stale client"); + return; + } + + client->recognitionCallback(halEvent); +} + +Return<void> SoundTriggerHw::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) { + ALOGV("getProperties() mHwDevice %p", mHwDevice); + int ret; + struct sound_trigger_properties halProperties; + ISoundTriggerHw::Properties properties; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + ret = mHwDevice->get_properties(mHwDevice, &halProperties); + + convertPropertiesFromHal(&properties, &halProperties); + + ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(), + properties.recognitionModes); + +exit: + _hidl_cb(ret, properties); + return Void(); +} + +int SoundTriggerHw::doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + sp<SoundTriggerHw::SoundModelClient> client) { + int32_t ret = 0; + struct sound_trigger_sound_model* halSoundModel; + + ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size()); + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + halSoundModel = convertSoundModelToHal(&soundModel); + if (halSoundModel == NULL) { + ret = -EINVAL; + goto exit; + } + + sound_model_handle_t halHandle; + ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback_, client.get(), + &halHandle); + + free(halSoundModel); + + if (ret != 0) { + goto exit; + } + + client->setHalHandle(halHandle); + { + AutoMutex lock(mLock); + mClients.add(client->getId(), client); + } + +exit: + return ret; +} + +Return<void> SoundTriggerHw::loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + const sp<V2_0::ISoundTriggerHwCallback>& callback, + V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + ISoundTriggerHw::loadSoundModel_cb _hidl_cb) { + sp<SoundTriggerHw::SoundModelClient> client = + new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel(soundModel, client), client->getId()); + return Void(); +} + +Return<void> SoundTriggerHw::loadPhraseSoundModel( + const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<V2_0::ISoundTriggerHwCallback>& callback, + V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) { + sp<SoundTriggerHw::SoundModelClient> client = + new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel, client), + client->getId()); + return Void(); +} + +Return<int32_t> SoundTriggerHw::unloadSoundModel(int32_t modelHandle) { + int32_t ret; + sp<SoundTriggerHw::SoundModelClient> client; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle()); + + mClients.removeItem(modelHandle); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHw::startRecognition( + int32_t modelHandle, const V2_0::ISoundTriggerHw::RecognitionConfig& config, + const sp<V2_0::ISoundTriggerHwCallback>& /* callback */, int32_t /* cookie */) { + int32_t ret; + sp<SoundTriggerHw::SoundModelClient> client; + struct sound_trigger_recognition_config* halConfig; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + halConfig = + convertRecognitionConfigToHal((const V2_0::ISoundTriggerHw::RecognitionConfig*)&config); + + if (halConfig == NULL) { + ret = -EINVAL; + goto exit; + } + ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig, + recognitionCallback_, client.get()); + + free(halConfig); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHw::stopRecognition(int32_t modelHandle) { + int32_t ret; + sp<SoundTriggerHw::SoundModelClient> client; + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle()); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHw::stopAllRecognitions() { + int32_t ret; + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + ret = mHwDevice->stop_all_recognitions(mHwDevice); + +exit: + return ret; +} + +SoundTriggerHw::SoundTriggerHw() : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {} + +void SoundTriggerHw::onFirstRef() { + const hw_module_t* mod; + int rc; + + rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod); + if (rc != 0) { + ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID, + mModuleName, strerror(-rc)); + return; + } + rc = sound_trigger_hw_device_open(mod, &mHwDevice); + if (rc != 0) { + ALOGE("couldn't open sound trigger hw device in %s.%s (%s)", + SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc)); + mHwDevice = NULL; + return; + } + if (mHwDevice->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_1_3) { + ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version); + sound_trigger_hw_device_close(mHwDevice); + mHwDevice = NULL; + return; + } + + ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice); +} + +SoundTriggerHw::~SoundTriggerHw() { + if (mHwDevice != NULL) { + sound_trigger_hw_device_close(mHwDevice); + } +} + +uint32_t SoundTriggerHw::nextUniqueModelId() { + uint32_t modelId = 0; + { + AutoMutex lock(mLock); + do { + modelId = atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1, + memory_order_acq_rel); + } while (mClients.valueFor(modelId) != 0 && modelId != 0); + } + LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu", + mClients.size()); + return modelId; +} + +void SoundTriggerHw::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) { + uuid->timeLow = halUuid->timeLow; + uuid->timeMid = halUuid->timeMid; + uuid->versionAndTimeHigh = halUuid->timeHiAndVersion; + uuid->variantAndClockSeqHigh = halUuid->clockSeq; + memcpy(&uuid->node[0], &halUuid->node[0], 6); +} + +void SoundTriggerHw::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) { + halUuid->timeLow = uuid->timeLow; + halUuid->timeMid = uuid->timeMid; + halUuid->timeHiAndVersion = uuid->versionAndTimeHigh; + halUuid->clockSeq = uuid->variantAndClockSeqHigh; + memcpy(&halUuid->node[0], &uuid->node[0], 6); +} + +void SoundTriggerHw::convertPropertiesFromHal( + ISoundTriggerHw::Properties* properties, + const struct sound_trigger_properties* halProperties) { + properties->implementor = halProperties->implementor; + properties->description = halProperties->description; + properties->version = halProperties->version; + convertUuidFromHal(&properties->uuid, &halProperties->uuid); + properties->maxSoundModels = halProperties->max_sound_models; + properties->maxKeyPhrases = halProperties->max_key_phrases; + properties->maxUsers = halProperties->max_users; + properties->recognitionModes = halProperties->recognition_modes; + properties->captureTransition = halProperties->capture_transition; + properties->maxBufferMs = halProperties->max_buffer_ms; + properties->concurrentCapture = halProperties->concurrent_capture; + properties->triggerInEvent = halProperties->trigger_in_event; + properties->powerConsumptionMw = halProperties->power_consumption_mw; +} + +void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase, + const ISoundTriggerHw::Phrase* triggerPhrase) { + halTriggerPhrase->id = triggerPhrase->id; + halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes; + unsigned int i; + + halTriggerPhrase->num_users = + std::min((int)triggerPhrase->users.size(), SOUND_TRIGGER_MAX_USERS); + for (i = 0; i < halTriggerPhrase->num_users; i++) { + halTriggerPhrase->users[i] = triggerPhrase->users[i]; + } + + strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN); + strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN); +} + +struct sound_trigger_sound_model* SoundTriggerHw::convertSoundModelToHal( + const V2_0::ISoundTriggerHw::SoundModel* soundModel) { + struct sound_trigger_sound_model* halModel = NULL; + if (soundModel->type == V2_0::SoundModelType::KEYPHRASE) { + size_t allocSize = + sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size(); + struct sound_trigger_phrase_sound_model* halKeyPhraseModel = + static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL, + "malloc failed for size %zu in convertSoundModelToHal PHRASE", + allocSize); + + const V2_0::ISoundTriggerHw::PhraseSoundModel* keyPhraseModel = + reinterpret_cast<const V2_0::ISoundTriggerHw::PhraseSoundModel*>(soundModel); + + size_t i; + for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]); + } + halKeyPhraseModel->num_phrases = (unsigned int)i; + halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel); + halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model); + } else { + size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size(); + halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halModel == NULL, + "malloc failed for size %zu in convertSoundModelToHal GENERIC", + allocSize); + + halModel->data_offset = sizeof(struct sound_trigger_sound_model); + } + halModel->type = (sound_trigger_sound_model_type_t)soundModel->type; + convertUuidToHal(&halModel->uuid, &soundModel->uuid); + convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid); + halModel->data_size = soundModel->data.size(); + uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset; + const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]); + memcpy(dst, src, soundModel->data.size()); + + return halModel; +} + +void SoundTriggerHw::convertPhraseRecognitionExtraToHal( + struct sound_trigger_phrase_recognition_extra* halExtra, + const V2_0::PhraseRecognitionExtra* extra) { + halExtra->id = extra->id; + halExtra->recognition_modes = extra->recognitionModes; + halExtra->confidence_level = extra->confidenceLevel; + + unsigned int i; + for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) { + halExtra->levels[i].user_id = extra->levels[i].userId; + halExtra->levels[i].level = extra->levels[i].levelPercent; + } + halExtra->num_levels = i; +} + +struct sound_trigger_recognition_config* SoundTriggerHw::convertRecognitionConfigToHal( + const V2_0::ISoundTriggerHw::RecognitionConfig* config) { + size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size(); + struct sound_trigger_recognition_config* halConfig = + static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize)); + + LOG_ALWAYS_FATAL_IF(halConfig == NULL, + "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize); + + halConfig->capture_handle = (audio_io_handle_t)config->captureHandle; + halConfig->capture_device = (audio_devices_t)config->captureDevice; + halConfig->capture_requested = config->captureRequested; + + unsigned int i; + for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]); + } + halConfig->num_phrases = i; + + halConfig->data_offset = sizeof(struct sound_trigger_recognition_config); + halConfig->data_size = config->data.size(); + uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset; + const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]); + memcpy(dst, src, config->data.size()); + return halConfig; +} + +// static +void SoundTriggerHw::convertSoundModelEventFromHal( + V2_0::ISoundTriggerHwCallback::ModelEvent* event, + const struct sound_trigger_model_event* halEvent) { + event->status = (V2_0::ISoundTriggerHwCallback::SoundModelStatus)halEvent->status; + // event->model to be remapped by called + event->data.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + + halEvent->data_offset, + halEvent->data_size); +} + +// static +void SoundTriggerHw::convertPhaseRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event, + const struct sound_trigger_phrase_recognition_event* halEvent) { + event->phraseExtras.resize(halEvent->num_phrases); + for (unsigned int i = 0; i < halEvent->num_phrases; i++) { + convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]); + } + convertRecognitionEventFromHal(&event->common, &halEvent->common); +} + +// static +void SoundTriggerHw::convertRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::RecognitionEvent* event, + const struct sound_trigger_recognition_event* halEvent) { + event->status = static_cast<V2_0::ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status); + event->type = static_cast<V2_0::SoundModelType>(halEvent->type); + // event->model to be remapped by called + event->captureAvailable = halEvent->capture_available; + event->captureSession = halEvent->capture_session; + event->captureDelayMs = halEvent->capture_delay_ms; + event->capturePreambleMs = halEvent->capture_preamble_ms; + event->triggerInData = halEvent->trigger_in_data; + event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate; + event->audioConfig.channelMask = + (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask; + event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format; + event->data.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + + halEvent->data_offset, + halEvent->data_size); +} + +// static +void SoundTriggerHw::convertPhraseRecognitionExtraFromHal( + V2_0::PhraseRecognitionExtra* extra, + const struct sound_trigger_phrase_recognition_extra* halExtra) { + extra->id = halExtra->id; + extra->recognitionModes = halExtra->recognition_modes; + extra->confidenceLevel = halExtra->confidence_level; + + extra->levels.resize(halExtra->num_levels); + for (unsigned int i = 0; i < halExtra->num_levels; i++) { + extra->levels[i].userId = halExtra->levels[i].user_id; + extra->levels[i].levelPercent = halExtra->levels[i].level; + } +} + +void SoundTriggerHw::SoundModelClient_2_0::recognitionCallback( + struct sound_trigger_recognition_event* halEvent) { + if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event; + convertPhaseRecognitionEventFromHal( + &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent)); + event.common.model = mId; + mCallback->phraseRecognitionCallback(event, mCookie); + } else { + V2_0::ISoundTriggerHwCallback::RecognitionEvent event; + convertRecognitionEventFromHal(&event, halEvent); + event.model = mId; + mCallback->recognitionCallback(event, mCookie); + } +} + +void SoundTriggerHw::SoundModelClient_2_0::soundModelCallback( + struct sound_trigger_model_event* halEvent) { + V2_0::ISoundTriggerHwCallback::ModelEvent event; + convertSoundModelEventFromHal(&event, halEvent); + event.model = mId; + mCallback->soundModelCallback(event, mCookie); +} + +// Begin V2_1 implementation, copied from +// hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.cpp + +namespace { + +// Backs up by the vector with the contents of shared memory. +// It is assumed that the passed hidl_vector is empty, so it's +// not cleared if the memory is a null object. +// The caller needs to keep the returned sp<IMemory> as long as +// the data is needed. +std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) { + sp<IMemory> memory; + if (m.size() == 0) { + return std::make_pair(true, memory); + } + memory = mapMemory(m); + if (memory != nullptr) { + memory->read(); + vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())), + memory->getSize()); + return std::make_pair(true, memory); + } + ALOGE("%s: Could not map HIDL memory to IMemory", __func__); + return std::make_pair(false, memory); +} + +// Moves the data from the vector into allocated shared memory, +// emptying the vector. +// It is assumed that the passed hidl_memory is a null object, so it's +// not reset if the vector is empty. +// The caller needs to keep the returned sp<IMemory> as long as +// the data is needed. +std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) { + sp<IMemory> memory; + if (v->size() == 0) { + return std::make_pair(true, memory); + } + sp<IAllocator> ashmem = IAllocator::getService("ashmem"); + if (ashmem == 0) { + ALOGE("Failed to retrieve ashmem allocator service"); + return std::make_pair(false, memory); + } + bool success = false; + Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) { + success = s; + if (success) *mem = m; + }); + if (r.isOk() && success) { + memory = hardware::mapMemory(*mem); + if (memory != 0) { + memory->update(); + memcpy(memory->getPointer(), v->data(), v->size()); + memory->commit(); + v->resize(0); + return std::make_pair(true, memory); + } else { + ALOGE("Failed to map allocated ashmem"); + } + } else { + ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size()); + } + return std::make_pair(false, memory); +} + +} // namespace + +Return<void> SoundTriggerHw::loadSoundModel_2_1( + const V2_1::ISoundTriggerHw::SoundModel& soundModel, + const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie, + V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) { + // It is assumed that legacy data vector is empty, thus making copy is cheap. + V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header); + auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data); + if (result.first) { + sp<SoundModelClient> client = + new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId()); + return Void(); + } + _hidl_cb(-ENOMEM, 0); + return Void(); +} + +Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1( + const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie, + V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) { + V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0; + // It is assumed that legacy data vector is empty, thus making copy is cheap. + soundModel_2_0.common = soundModel.common.header; + // Avoid copying phrases data. + soundModel_2_0.phrases.setToExternal( + const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()), + soundModel.phrases.size()); + auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data); + if (result.first) { + sp<SoundModelClient> client = + new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback); + _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client), + client->getId()); + return Void(); + } + _hidl_cb(-ENOMEM, 0); + return Void(); +} + +Return<int32_t> SoundTriggerHw::startRecognition_2_1( + int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config, + const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie) { + // It is assumed that legacy data vector is empty, thus making copy is cheap. + V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header); + auto result = memoryAsVector(config.data, &config_2_0.data); + return result.first ? startRecognition(modelHandle, config_2_0, callback, cookie) + : Return<int32_t>(-ENOMEM); +} + +void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback( + struct sound_trigger_recognition_event* halEvent) { + if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0; + convertPhaseRecognitionEventFromHal( + &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent)); + event_2_0.common.model = mId; + V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event; + event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(), + event_2_0.phraseExtras.size()); + auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data); + if (result.first) { + // The data vector is now empty, thus copying is cheap. + event.common.header = event_2_0.common; + mCallback->phraseRecognitionCallback_2_1(event, mCookie); + } + } else { + V2_1::ISoundTriggerHwCallback::RecognitionEvent event; + convertRecognitionEventFromHal(&event.header, halEvent); + event.header.model = mId; + auto result = moveVectorToMemory(&event.header.data, &event.data); + if (result.first) { + mCallback->recognitionCallback_2_1(event, mCookie); + } + } +} + +void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback( + struct sound_trigger_model_event* halEvent) { + V2_1::ISoundTriggerHwCallback::ModelEvent event; + convertSoundModelEventFromHal(&event.header, halEvent); + event.header.model = mId; + auto result = moveVectorToMemory(&event.header.data, &event.data); + if (result.first) { + mCallback->soundModelCallback_2_1(event, mCookie); + } +} + +// Begin V2_2 implementation, copied from +// hardware/interfaces/soundtrigger/2.2/default/SoundTriggerHw.cpp + +Return<int32_t> SoundTriggerHw::getModelState(int32_t modelHandle) { + sp<SoundModelClient> client; + if (mHwDevice == NULL) { + return -ENODEV; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + return -ENOSYS; + } + } + + return mHwDevice->get_model_state(mHwDevice, client->getHalHandle()); +} + +// Begin V2_3 implementation + +Return<int32_t> SoundTriggerHw::setParameter(V2_0::SoundModelHandle modelHandle, + ModelParameter modelParam, int32_t value) { + sp<SoundModelClient> client; + if (mHwDevice == NULL) { + return -ENODEV; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + return -EINVAL; + } + } + + return mHwDevice->set_parameter(mHwDevice, client->getHalHandle(), + convertModelParameterToHal(modelParam), value); +} + +Return<void> SoundTriggerHw::getParameter(V2_0::SoundModelHandle modelHandle, + ModelParameter modelParam, getParameter_cb _hidl_cb) { + sp<SoundModelClient> client; + if (mHwDevice == NULL) { + _hidl_cb(-ENODEV, 0); + return Void(); + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + _hidl_cb(-EINVAL, 0); + return Void(); + } + } + + int32_t value; + int32_t status = mHwDevice->get_parameter(mHwDevice, client->getHalHandle(), + convertModelParameterToHal(modelParam), &value); + _hidl_cb(status, value); + return Void(); +} + +Return<void> SoundTriggerHw::queryParameter(V2_0::SoundModelHandle modelHandle, + ModelParameter modelParam, queryParameter_cb _hidl_cb) { + OptionalModelParameterRange optionalParamRange; + sp<SoundModelClient> client; + if (mHwDevice == NULL) { + _hidl_cb(-ENODEV, optionalParamRange); + return Void(); + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + _hidl_cb(-EINVAL, optionalParamRange); + return Void(); + } + } + + sound_trigger_model_parameter_range_t paramRange; + int32_t status = mHwDevice->query_parameter( + mHwDevice, client->getHalHandle(), convertModelParameterToHal(modelParam), ¶mRange); + + if (status == 0) { + optionalParamRange.range({.start = paramRange.start, .end = paramRange.end}); + } + _hidl_cb(status, optionalParamRange); + return Void(); +} + +// static +sound_trigger_model_parameter_t SoundTriggerHw::convertModelParameterToHal(ModelParameter param) { + switch (param) { + case ModelParameter::THRESHOLD_FACTOR: + return MODEL_PARAMETER_THRESHOLD_FACTOR; + case ModelParameter::INVALID: + default: + return MODEL_PARAMETER_INVALID; + } +} + +// Methods from ::android::hidl::base::V1_0::IBase follow. + +ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) { + return new SoundTriggerHw(); +} + +} // namespace implementation +} // namespace V2_3 +} // namespace soundtrigger +} // namespace hardware +} // namespace android diff --git a/soundtrigger/2.3/default/SoundTriggerHw.h b/soundtrigger/2.3/default/SoundTriggerHw.h new file mode 100644 index 0000000000..c82c9ea0e2 --- /dev/null +++ b/soundtrigger/2.3/default/SoundTriggerHw.h @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_V2_3_SOUNDTRIGGERHW_H +#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_3_SOUNDTRIGGERHW_H + +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h> +#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h> +#include <android/hardware/soundtrigger/2.3/types.h> +#include <hardware/sound_trigger.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <stdatomic.h> +#include <system/sound_trigger.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> + +namespace android { +namespace hardware { +namespace soundtrigger { +namespace V2_3 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::audio::common::V2_0::Uuid; + +/** + * According to the HIDL C++ Users Guide: client and server implementations + * should never directly refer to anything other than the interface header + * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so + * this V2_3 implementation copies the previous implementations and + * then adds the new implementation. + */ +struct SoundTriggerHw : public ISoundTriggerHw { + // Methods from V2_0::ISoundTriggerHw follow. + Return<void> getProperties(getProperties_cb _hidl_cb) override; + Return<void> loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + const sp<V2_0::ISoundTriggerHwCallback>& callback, int32_t cookie, + loadSoundModel_cb _hidl_cb) override; + Return<void> loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<V2_0::ISoundTriggerHwCallback>& callback, + int32_t cookie, loadPhraseSoundModel_cb _hidl_cb) override; + Return<int32_t> unloadSoundModel(int32_t modelHandle) override; + Return<int32_t> startRecognition(int32_t modelHandle, + const V2_0::ISoundTriggerHw::RecognitionConfig& config, + const sp<V2_0::ISoundTriggerHwCallback>& callback, + int32_t cookie) override; + Return<int32_t> stopRecognition(int32_t modelHandle) override; + Return<int32_t> stopAllRecognitions() override; + + // Methods from V2_1::ISoundTriggerHw follow. + Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel, + const sp<V2_1::ISoundTriggerHwCallback>& callback, + int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override; + Return<void> loadPhraseSoundModel_2_1(const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<V2_1::ISoundTriggerHwCallback>& callback, + int32_t cookie, + loadPhraseSoundModel_2_1_cb _hidl_cb) override; + Return<int32_t> startRecognition_2_1(int32_t modelHandle, + const V2_1::ISoundTriggerHw::RecognitionConfig& config, + const sp<V2_1::ISoundTriggerHwCallback>& callback, + int32_t cookie) override; + + // Methods from V2_2::ISoundTriggerHw follow. + Return<int32_t> getModelState(int32_t modelHandle) override; + + // Methods from V2_3::ISoundTriggerHw follow. + Return<int32_t> setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, + int32_t value) override; + Return<void> getParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, + ISoundTriggerHw::getParameter_cb _hidl_cb) override; + Return<void> queryParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam, + ISoundTriggerHw::queryParameter_cb _hidl_cb) override; + + SoundTriggerHw(); + + // Copied from hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.h + + /** + * Client object holding active handles and callback sctructures. Used for referencing + * which models map to which client of the HAL. SoundModelClients are stored in the + * mClients object while the model is active. + */ + class SoundModelClient : public RefBase { + public: + SoundModelClient(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie) + : mId(id), mCookie(cookie) {} + virtual ~SoundModelClient() {} + + uint32_t getId() const { return mId; } + sound_model_handle_t getHalHandle() const { return mHalHandle; } + void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; } + + virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0; + virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0; + + protected: + const uint32_t mId; + sound_model_handle_t mHalHandle; + V2_0::ISoundTriggerHwCallback::CallbackCookie mCookie; + }; + + private: + static void convertPhaseRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event, + const struct sound_trigger_phrase_recognition_event* halEvent); + static void convertRecognitionEventFromHal( + V2_0::ISoundTriggerHwCallback::RecognitionEvent* event, + const struct sound_trigger_recognition_event* halEvent); + static void convertSoundModelEventFromHal(V2_0::ISoundTriggerHwCallback::ModelEvent* event, + const struct sound_trigger_model_event* halEvent); + + virtual ~SoundTriggerHw(); + + uint32_t nextUniqueModelId(); + int doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel, + sp<SoundModelClient> client); + + // RefBase + void onFirstRef() override; + + class SoundModelClient_2_0 : public SoundModelClient { + public: + SoundModelClient_2_0(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie, + sp<V2_0::ISoundTriggerHwCallback> callback) + : SoundModelClient(id, cookie), mCallback(callback) {} + + void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override; + void soundModelCallback(struct sound_trigger_model_event* halEvent) override; + + private: + sp<V2_0::ISoundTriggerHwCallback> mCallback; + }; + + void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid); + void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid); + void convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties* properties, + const struct sound_trigger_properties* halProperties); + static sound_trigger_model_parameter_t convertModelParameterToHal(ModelParameter param); + void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase, + const V2_0::ISoundTriggerHw::Phrase* triggerPhrase); + // returned HAL sound model must be freed by caller + struct sound_trigger_sound_model* convertSoundModelToHal( + const V2_0::ISoundTriggerHw::SoundModel* soundModel); + void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra, + const V2_0::PhraseRecognitionExtra* extra); + // returned recognition config must be freed by caller + struct sound_trigger_recognition_config* convertRecognitionConfigToHal( + const V2_0::ISoundTriggerHw::RecognitionConfig* config); + + static void convertPhraseRecognitionExtraFromHal( + V2_0::PhraseRecognitionExtra* extra, + const struct sound_trigger_phrase_recognition_extra* halExtra); + + static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie); + static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie); + + const char* mModuleName; + struct sound_trigger_hw_device* mHwDevice; + volatile atomic_uint_fast32_t mNextModelId; + DefaultKeyedVector<int32_t, sp<SoundModelClient>> mClients; + Mutex mLock; + + // Copied from hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.h + class SoundModelClient_2_1 : public SoundModelClient { + public: + SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie, + sp<V2_1::ISoundTriggerHwCallback> callback) + : SoundModelClient(id, cookie), mCallback(callback) {} + + void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override; + void soundModelCallback(struct sound_trigger_model_event* halEvent) override; + + private: + sp<V2_1::ISoundTriggerHwCallback> mCallback; + }; +}; + +extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name); + +} // namespace implementation +} // namespace V2_3 +} // namespace soundtrigger +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal new file mode 100644 index 0000000000..c3a522b31f --- /dev/null +++ b/soundtrigger/2.3/types.hal @@ -0,0 +1,61 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.soundtrigger@2.3; + +import android.hidl.safe_union@1.0::Monostate; + +/** + * Model specific parameters to be used with parameter set and get APIs + */ +enum ModelParameter : int32_t { + /** + * Placeholder for invalid model parameter used for returning error or + * passing an invalid value. + */ + INVALID = -1, + + /** + * Controls the sensitivity threshold adjustment factor for a given model. + * Negative value corresponds to less sensitive model (high threshold) and + * a positive value corresponds to a more sensitive model (low threshold). + * Default value is 0. + */ + THRESHOLD_FACTOR = 0 +}; + +/** + * Safe union wrapping ModelParameterRange. + * Monostate is used to indicate there is no valid range + */ +safe_union OptionalModelParameterRange { + Monostate noinit; + ModelParameterRange range; +}; + +/** + * Model specific range support for a given parameter + */ +struct ModelParameterRange { + /** + * start of supported value range inclusive + */ + int32_t start; + /** + * end of supported value range inclusive + */ + int32_t end; +}; diff --git a/soundtrigger/2.3/vts/functional/Android.bp b/soundtrigger/2.3/vts/functional/Android.bp new file mode 100644 index 0000000000..e3855fc372 --- /dev/null +++ b/soundtrigger/2.3/vts/functional/Android.bp @@ -0,0 +1,31 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_test { + name: "VtsHalSoundtriggerV2_3TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalSoundtriggerV2_3TargetTest.cpp"], + static_libs: [ + "android.hardware.soundtrigger@2.0", + "android.hardware.soundtrigger@2.1", + "android.hardware.soundtrigger@2.2", + "android.hardware.soundtrigger@2.3", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp new file mode 100644 index 0000000000..202eb6c09b --- /dev/null +++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SoundTriggerHidlHalTest" + +#include <android-base/logging.h> +#include <android/hardware/audio/common/2.0/types.h> +#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h> +#include <android/hardware/soundtrigger/2.3/types.h> +#include <gtest/gtest.h> +#include <hidl/GtestPrinter.h> +#include <hidl/ServiceManagement.h> + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::soundtrigger::V2_3::ISoundTriggerHw; + +/** + * Test class holding the instance of the SoundTriggerHW service to test. + * The passed parameter is the registered name of the implementing service + * supplied by INSTANTIATE_TEST_SUITE_P() call. + */ +class SoundTriggerHidlTest : public testing::TestWithParam<std::string> { + public: + void SetUp() override { + soundtrigger = ISoundTriggerHw::getService(GetParam()); + + ASSERT_NE(soundtrigger, nullptr); + LOG(INFO) << "Test is remote " << soundtrigger->isRemote(); + } + + sp<ISoundTriggerHw> soundtrigger; +}; + +/** + * Empty test is in place to ensure service is initalized. + * Due to the nature of SoundTrigger HAL providing an interface for + * proprietary or vendor specific implementations, limited testing on + * individual APIs is possible. + */ +TEST_P(SoundTriggerHidlTest, ServiceIsInstantiated) {} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, SoundTriggerHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)), + android::hardware::PrintInstanceNameToString); |