mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
Adding getModelState API to sound trigger with new build fix.
This version copies the V2_0 and V2_1 implementations instead of trying to extend them. Test: built with the forrest tool, ie. forrest --force_cherry_pick \ build th:cl:5288240:aosp_x86-eng:git_master-without-vendor Change-Id: Iec18b6a29c8d3d495b24fc07b5f7db95a8057f30 Bug-Id: 70206501
This commit is contained in:
20
soundtrigger/2.2/Android.bp
Normal file
20
soundtrigger/2.2/Android.bp
Normal file
@@ -0,0 +1,20 @@
|
||||
// This file is autogenerated by hidl-gen -Landroidbp.
|
||||
|
||||
hidl_interface {
|
||||
name: "android.hardware.soundtrigger@2.2",
|
||||
root: "android.hardware",
|
||||
vndk: {
|
||||
enabled: true,
|
||||
},
|
||||
srcs: [
|
||||
"ISoundTriggerHw.hal",
|
||||
],
|
||||
interfaces: [
|
||||
"android.hardware.audio.common@2.0",
|
||||
"android.hardware.soundtrigger@2.0",
|
||||
"android.hardware.soundtrigger@2.1",
|
||||
"android.hidl.base@1.0",
|
||||
],
|
||||
gen_java: false,
|
||||
}
|
||||
|
||||
40
soundtrigger/2.2/ISoundTriggerHw.hal
Normal file
40
soundtrigger/2.2/ISoundTriggerHw.hal
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2018 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.2;
|
||||
|
||||
import @2.0::ISoundTriggerHwCallback.RecognitionEvent;
|
||||
import @2.0::SoundModelHandle;
|
||||
import @2.1::ISoundTriggerHw;
|
||||
|
||||
/**
|
||||
* SoundTrigger HAL interface. Used for hardware recognition of hotwords.
|
||||
*/
|
||||
interface ISoundTriggerHw extends @2.1::ISoundTriggerHw {
|
||||
|
||||
/**
|
||||
* Get the state of a given model.
|
||||
* The model state is returned as a RecognitionEvent.
|
||||
* @param modelHandle The handle of the sound model to use for recognition
|
||||
* @return retval Operation completion status: 0 in case of success,
|
||||
* -ENOSYS in case of invalid model handle,
|
||||
* -ENOMEM in case of memory allocation failure,
|
||||
* -ENODEV in case of initialization error.
|
||||
* @return state RecognitionEvent in case of success
|
||||
*/
|
||||
getModelState(SoundModelHandle modelHandle)
|
||||
generates (int32_t retval, @2.0::ISoundTriggerHwCallback.RecognitionEvent state);
|
||||
};
|
||||
37
soundtrigger/2.2/default/Android.bp
Normal file
37
soundtrigger/2.2/default/Android.bp
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright (C) 2018 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.2-impl",
|
||||
relative_install_path: "hw",
|
||||
vendor: true,
|
||||
srcs: [
|
||||
"SoundTriggerHw.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libhidlbase",
|
||||
"libhidltransport",
|
||||
"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.hidl.allocator@1.0",
|
||||
"android.hidl.memory@1.0",
|
||||
],
|
||||
}
|
||||
744
soundtrigger/2.2/default/SoundTriggerHw.cpp
Normal file
744
soundtrigger/2.2/default/SoundTriggerHw.cpp
Normal file
@@ -0,0 +1,744 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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_2 {
|
||||
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_2 implementation copies the V2_0 and V2_1 implementations and
|
||||
* then adds the new V2_2 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;
|
||||
}
|
||||
|
||||
if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
|
||||
mHwDevice->stop_all_recognitions) {
|
||||
ret = mHwDevice->stop_all_recognitions(mHwDevice);
|
||||
} else {
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
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_0 ||
|
||||
mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
|
||||
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 ISoundTriggerHw::PhraseSoundModel* keyPhraseModel =
|
||||
reinterpret_cast<const 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
|
||||
|
||||
Return<void> SoundTriggerHw::getModelState(int32_t modelHandle, getModelState_cb hidl_cb) {
|
||||
int ret = 0;
|
||||
V2_0::ISoundTriggerHwCallback::RecognitionEvent event;
|
||||
struct sound_trigger_recognition_event* halEvent = NULL;
|
||||
sp<SoundModelClient> client;
|
||||
if (mHwDevice == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
{
|
||||
AutoMutex lock(mLock);
|
||||
client = mClients.valueFor(modelHandle);
|
||||
if (client == 0) {
|
||||
ret = -ENOSYS;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (mHwDevice->get_model_state == NULL) {
|
||||
ALOGE("Failed to get model state from device, no such method");
|
||||
ret = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Get the state from the device (as a recognition event)
|
||||
halEvent = mHwDevice->get_model_state(mHwDevice, client->getHalHandle());
|
||||
if (halEvent == NULL) {
|
||||
ALOGE("Failed to get model state from device");
|
||||
ret = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
convertRecognitionEventFromHal(&event, halEvent);
|
||||
|
||||
exit:
|
||||
hidl_cb(ret, event);
|
||||
free(halEvent);
|
||||
return Void();
|
||||
}
|
||||
|
||||
// Methods from ::android::hidl::base::V1_0::IBase follow.
|
||||
|
||||
ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) {
|
||||
return new SoundTriggerHw();
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V2_2
|
||||
} // namespace soundtrigger
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
193
soundtrigger/2.2/default/SoundTriggerHw.h
Normal file
193
soundtrigger/2.2/default/SoundTriggerHw.h
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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_2_SOUNDTRIGGERHW_H
|
||||
#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H
|
||||
|
||||
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
|
||||
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
|
||||
#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.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_2 {
|
||||
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;
|
||||
using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
|
||||
|
||||
/**
|
||||
* 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_2 implementation copies the V2_0 and V2_1 implementations and
|
||||
* then adds the new V2_2 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<void> getModelState(int32_t modelHandle, getModelState_cb _hidl_cb) override;
|
||||
|
||||
SoundTriggerHw();
|
||||
|
||||
// Copied from hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.h
|
||||
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;
|
||||
};
|
||||
|
||||
protected:
|
||||
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;
|
||||
|
||||
private:
|
||||
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);
|
||||
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_2
|
||||
} // namespace soundtrigger
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <cutils/native_handle.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include <android/hardware/audio/common/2.0/types.h>
|
||||
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
|
||||
#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
|
||||
|
||||
#include <VtsHalHidlTargetTestBase.h>
|
||||
#include <VtsHalHidlTargetTestEnvBase.h>
|
||||
|
||||
using ::android::sp;
|
||||
using ::android::hardware::Return;
|
||||
using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
|
||||
using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
|
||||
using ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw;
|
||||
|
||||
// Test environment for SoundTrigger HIDL HAL.
|
||||
class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
|
||||
public:
|
||||
// get the test environment singleton
|
||||
static SoundTriggerHidlEnvironment* Instance() {
|
||||
static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
|
||||
|
||||
private:
|
||||
SoundTriggerHidlEnvironment() {}
|
||||
};
|
||||
|
||||
// The main test class for Sound Trigger HIDL HAL.
|
||||
class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
|
||||
public:
|
||||
void SetUp() override {
|
||||
mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
|
||||
SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
|
||||
ASSERT_NE(nullptr, mSoundTriggerHal.get());
|
||||
}
|
||||
|
||||
static void SetUpTestCase() { srand(1234); }
|
||||
|
||||
void TearDown() override {}
|
||||
|
||||
protected:
|
||||
sp<ISoundTriggerHw> mSoundTriggerHal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test ISoundTriggerHw::getModelState() method
|
||||
*
|
||||
* Verifies that:
|
||||
* - the implementation returns -EINVAL with invalid model handle
|
||||
*
|
||||
*/
|
||||
TEST_F(SoundTriggerHidlTest, GetModelStateInvalidModel) {
|
||||
int ret = android::OK;
|
||||
::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback::RecognitionEvent event;
|
||||
SoundModelHandle handle = 0;
|
||||
Return<void> hidlReturn =
|
||||
mSoundTriggerHal->getModelState(handle, [&](int32_t retval, auto res) {
|
||||
ret = retval;
|
||||
event = res;
|
||||
});
|
||||
|
||||
EXPECT_TRUE(hidlReturn.isOk());
|
||||
EXPECT_EQ(-ENOSYS, ret);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
|
||||
int status = RUN_ALL_TESTS();
|
||||
ALOGI("Test result = %d", status);
|
||||
return status;
|
||||
}
|
||||
Reference in New Issue
Block a user