/* * 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 #include #include #include 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_1 { namespace implementation { 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 as long as // the data is needed. std::pair> memoryAsVector(const hidl_memory& m, hidl_vec* vec) { sp memory; if (m.size() == 0) { return std::make_pair(true, memory); } memory = mapMemory(m); if (memory != nullptr) { memory->read(); vec->setToExternal(static_cast(static_cast(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 as long as // the data is needed. std::pair> moveVectorToMemory(hidl_vec* v, hidl_memory* mem) { sp memory; if (v->size() == 0) { return std::make_pair(true, memory); } sp ashmem = IAllocator::getService("ashmem"); if (ashmem == 0) { ALOGE("Failed to retrieve ashmem allocator service"); return std::make_pair(false, memory); } bool success = false; Return 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 SoundTriggerHw::loadSoundModel_2_1( const V2_1::ISoundTriggerHw::SoundModel& soundModel, const sp& 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 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 SoundTriggerHw::loadPhraseSoundModel_2_1( const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel, const sp& 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(soundModel.phrases.data()), soundModel.phrases.size()); auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data); if (result.first) { sp 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 SoundTriggerHw::startRecognition_2_1( int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config) { // 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) : Return(-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(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); } } ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) { return (new SoundTriggerHw())->getInterface(); } } // namespace implementation } // namespace V2_1 } // namespace soundtrigger } // namespace hardware } // namespace android