only first

Signed-off-by: 郝庆屺 <wangda_24@live.com>
This commit is contained in:
郝庆屺
2025-07-15 11:19:19 +08:00
parent d34bbfa03e
commit e4ffe80e5e
18 changed files with 1107 additions and 9 deletions
+2 -1
View File
@@ -52,7 +52,8 @@
"intelligent_voice_framework_only_first_stage",
"intelligent_voice_framework_only_second_stage",
"intelligent_voice_framework_window_manager_enable",
"intelligent_voice_framework_power_manager_enable"
"intelligent_voice_framework_power_manager_enable",
"intelligent_voice_framework_first_stage_oneshot_enable"
],
"build": {
"sub_component": [
+1
View File
@@ -19,6 +19,7 @@ declare_args() {
intelligent_voice_framework_only_second_stage = false
intelligent_voice_framework_window_manager_enable = false
intelligent_voice_framework_power_manager_enable = false
intelligent_voice_framework_first_stage_oneshot_enable = false
if (defined(global_parts_info) &&
defined(global_parts_info.telephony_state_registry) &&
defined(global_parts_info.telephony_core_service) &&
+47
View File
@@ -102,6 +102,44 @@ ohos_source_set("engine_source") {
"safwk:system_ability_fwk",
"samgr:samgr_proxy",
]
} else if (intelligent_voice_framework_first_stage_oneshot_enable) {
sources = [
"server/base/audio_debug.cpp",
"server/base/audio_source.cpp",
"server/base/engine_base.cpp",
"server/base/file_source.cpp",
"server/base/intell_voice_engine_stub.cpp",
"server/manager/engine_callback_message.cpp",
"server/manager/only_first_engine_manager.cpp",
"server/wakeup/only_first/only_first_wakeup_engine.cpp",
"server/wakeup/only_first/only_first_wakeup_engine_impl.cpp",
"server/wakeup/wakeup_source_process.cpp",
"server/wakeup/wakeup_source_stop_callback.cpp",
]
include_dirs = [
"inc",
"../../../../ai/intelligent_voice_framework/utils",
"../../../../ai/intelligent_voice_framework/interfaces/inner_api/native",
"../intell_voice_service/inc",
"intell_voice_engine",
"server/base",
"server/utils",
"server/wakeup",
"server/wakeup/only_first",
]
external_deps = [
"audio_framework:audio_capturer",
"audio_framework:audio_client",
"audio_framework:audio_foundation",
"c_utils:utils",
"eventhandler:libeventhandler",
"ffrt:libffrt",
"hilog:libhilog",
"image_framework:image_native",
"ipc:ipc_core",
]
} else {
sources = [
"server/manager/dummy_engine_manager.cpp",
@@ -126,6 +164,13 @@ ohos_source_set("engine_source") {
cflags_cc += [ "-DONLY_SECOND_STAGE" ]
}
if (intelligent_voice_framework_only_first_stage) {
cflags_cc += [ "-DONLY_FIRST_STAGE" ]
if (intelligent_voice_framework_first_stage_oneshot_enable) {
cflags_cc += [ "-DFIRST_STAGE_ONESHOT_ENABLE" ]
}
}
defines = []
if (build_variant == "root") {
defines += [ "INTELL_VOICE_BUILD_VARIANT_ROOT" ]
@@ -150,6 +195,8 @@ ohos_shared_library("intelligentvoice_engine") {
external_deps = [ "hilog:libhilog" ]
if (intelligent_voice_framework_engine_enable) {
version_script = "libintelligentvoice_engine.versionscript"
} else if (intelligent_voice_framework_first_stage_oneshot_enable) {
version_script = "libintelligentvoice_only_first_engine.versionscript"
} else {
version_script = "libintelligentvoice_dummy_engine.versionscript"
}
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* 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 ONLY_FIRST_ENGINE_MANAGER_H
#define ONLY_FIRST_ENGINE_MANAGER_H
#include <mutex>
#include "engine_base.h"
#include "i_intell_voice_engine.h"
#include "i_intell_voice_service.h"
#include "intell_voice_definitions.h"
#include "intell_voice_death_recipient.h"
namespace OHOS {
namespace IntellVoiceEngine {
class OnlyFirstEngineManager {
public:
OnlyFirstEngineManager();
~OnlyFirstEngineManager();
void SetScreenOff(bool value) {};
static bool GetEnrollResult(IntellVoiceEngineType type) { return false; };
int32_t GetWakeupSourceFilesList(std::vector<std::string> &cloneFiles) { return 0; };
int32_t GetWakeupSourceFile(const std::string &filePath, std::vector<uint8_t> &buffer) { return 0; };
int32_t SendWakeupFile(const std::string &filePath, const std::vector<uint8_t> &buffer) { return 0; };
int32_t GetUploadFiles(int numMax, std::vector<UploadFilesFromHdi> &files) { return 0; };
void ClearUserDataInner() {};
void HeadsetHostDie() {};
bool IsNeedUpdateComplete(int32_t result, const std::string &param) { return false; };
bool IsNeedUpdateRetry() { return false; };
int32_t SilenceUpdate() { return 0; };
int32_t WhisperVprUpdate(bool reEnroll = false) { return 0; };
int32_t CloneUpdate(const std::string &wakeupInfo, const sptr<IRemoteObject> &object) { return 0; };
void SetDspSensibility(const std::string &sensibility) {};
void OnServiceStart() {};
void OnServiceStop() {};
void ClearWakeupEngineCb() {};
bool IsEngineExist(IntellVoiceEngineType type);
bool AnyEngineExist(const std::vector<IntellVoiceEngineType>& types);
bool RegisterProxyDeathRecipient(IntellVoiceEngineType type, const sptr<IRemoteObject> &object);
bool DeregisterProxyDeathRecipient(IntellVoiceEngineType type);
int32_t SetParameter(const std::string &keyValueList);
std::string GetParameter(const std::string &key);
void EngineOnDetected(int32_t uuid);
sptr<IIntellVoiceEngine> CreateEngine(IntellVoiceEngineType type, const std::string &param = "");
int32_t ReleaseEngineInner(IntellVoiceEngineType type);
bool CreateOrResetWakeupEngine();
int32_t ServiceStopProc();
private:
sptr<IIntellVoiceEngine> CreateEngineInner(IntellVoiceEngineType type);
private:
std::mutex deathMutex_;
sptr<EngineBase> wakeupEngine_ = nullptr;
sptr<IntellVoiceUtils::IntellVoiceDeathRecipient> proxyDeathRecipient_ = nullptr;
sptr<IRemoteObject> deathRecipientObj_ = nullptr;
};
} // namespace IntellVoiceEngine
} // namespace OHOS
#endif
@@ -0,0 +1,23 @@
# Copyright (c) 2025 Huawei Device Co., Ltd.
# 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.
1.0 {
global:
extern "C++" {
OHOS::IntellVoiceEngine::OnlyFirstEngineManager::*;
OHOS::IntellVoiceEngine::EngineCallbackMessage::EngineFuncMap;
std::__h::__any_imp::*;
};
local:
*;
};
@@ -79,12 +79,20 @@ bool AudioSource::Start()
isReading_.store(true);
CreateAudioDebugFile("_audio_source");
std::thread t1(std::bind(&AudioSource::ReadThread, this));
#ifdef FIRST_STAGE_ONESHOT_ENABLE
if (!ThreadWrapper::Start("WakeUpAudioSource")) {
INTELL_VOICE_LOG_ERROR("failed to start wakeup source");
return false;
}
#else
std::thread t1(std::bind(&AudioSource::Run, this));
readThread_ = std::move(t1);
#endif
return true;
}
void AudioSource::ReadThread()
void AudioSource::Run()
{
INTELL_VOICE_LOG_INFO("enter");
uint32_t readCnt = 0;
@@ -133,7 +141,11 @@ void AudioSource::Stop()
MemoryGuard memoryGuard;
isReading_.store(false);
#ifdef FIRST_STAGE_ONESHOT_ENABLE
ThreadWrapper::Join();
#else
readThread_.join();
#endif
DestroyAudioDebugFile();
@@ -22,6 +22,7 @@
#include "audio_capturer.h"
#include "audio_info.h"
#include "audio_debug.h"
#include "thread_wrapper.h"
namespace OHOS {
namespace IntellVoiceEngine {
@@ -35,7 +36,11 @@ struct AudioSourceListener {
OnBufferEndCb bufferEndCb_;
};
#ifdef FIRST_STAGE_ONESHOT_ENABLE
class AudioSource : public IntellVoiceUtils::ThreadWrapper, private AudioDebug {
#else
class AudioSource : private AudioDebug {
#endif
public:
AudioSource(uint32_t minBufferSize, uint32_t bufferCnt, std::unique_ptr<AudioSourceListener> listener,
const OHOS::AudioStandard::AudioCapturerOptions &capturerOptions);
@@ -44,7 +49,7 @@ public:
void Stop();
private:
void ReadThread();
void Run();
bool Read();
private:
@@ -0,0 +1,227 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* 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.
*/
#include "only_first_engine_manager.h"
#include <vector>
#include <fstream>
#include <cstdio>
#include "intell_voice_log.h"
#include "intell_voice_util.h"
#include "string_util.h"
#include "iservice_registry.h"
#include "intell_voice_generic_factory.h"
#include "memory_guard.h"
#include "engine_callback_message.h"
#include "intell_voice_definitions.h"
#include "only_first_wakeup_engine_obj.h"
#define LOG_TAG "OnlyFirstEngineManager"
using namespace OHOS::IntellVoiceUtils;
namespace OHOS {
namespace IntellVoiceEngine {
OnlyFirstEngineManager::OnlyFirstEngineManager()
{
}
OnlyFirstEngineManager::~OnlyFirstEngineManager()
{
}
bool OnlyFirstEngineManager::IsEngineExist(IntellVoiceEngineType type)
{
if(type == INTELL_VOICE_WAKEUP) {
if(wakeupEngine_ != nullptr) {
return true;
}
}
return false;
}
bool OnlyFirstEngineManager::AnyEngineExist(const std::vector<IntellVoiceEngineType>& types)
{
for (const auto &type : types) {
if (IsEngineExist(type)) {
return true;
}
}
return false;
}
bool OnlyFirstEngineManager::RegisterProxyDeathRecipient(IntellVoiceEngineType type, const sptr<IRemoteObject> &object)
{
std::lock_guard<std::mutex> lock(deathMutex_);
INTELL_VOICE_LOG_INFO("enter, type:%{public}d", type);
if (type != INTELL_VOICE_WAKEUP) {
INTELL_VOICE_LOG_ERROR("invalid type:%{public}d", type);
return false;
}
if(proxyDeathRecipient_ != nullptr) {
INTELL_VOICE_LOG_ERROR("death recipient is not nullptr, type:%{public}d", type);
return false;
}
deathRecipientObj_ = object;
proxyDeathRecipient_ = new (std::nothrow) IntellVoiceDeathRecipient([&]() {
INTELL_VOICE_LOG_INFO("receive wakeup proxy death recipient, clear wakeup engine callback");
EngineCallbackMessage::CallFunc(HANDLE_CLEAR_WAKEUP_ENGINE_CB);
});
if (proxyDeathRecipient_ == nullptr) {
INTELL_VOICE_LOG_ERROR("create death recipient failed");
return false;
}
return deathRecipientObj_->AddDeathRecipient(proxyDeathRecipient_);
}
bool OnlyFirstEngineManager::DeregisterProxyDeathRecipient(IntellVoiceEngineType type)
{
std::lock_guard<std::mutex> lock(deathMutex_);
INTELL_VOICE_LOG_INFO("enter, type:%{public}d", type);
if (type != INTELL_VOICE_WAKEUP) {
INTELL_VOICE_LOG_ERROR("invalid type:%{public}d", type);
return false;
}
if (deathRecipientObj_ == nullptr) {
INTELL_VOICE_LOG_ERROR("death obj is nullptr, type:%{public}d", type);
return false;
}
if (proxyDeathRecipient_ == nullptr) {
INTELL_VOICE_LOG_ERROR("death recipient is nullptr, type:%{public}d", type);
deathRecipientObj_ = nullptr;
return false;
}
auto ret = deathRecipientObj_->RemoveDeathRecipient(proxyDeathRecipient_);
deathRecipientObj_ = nullptr;
proxyDeathRecipient_ = nullptr;
return ret;
}
int32_t OnlyFirstEngineManager::SetParameter(const std::string &keyValueList)
{
if (wakeupEngine_ != nullptr) {
wakeupEngine_->SetParameter(keyValueList);
}
return 0;
}
std::string OnlyFirstEngineManager::GetParameter(const std::string &key)
{
std::string val = "";
if (wakeupEngine_ != nullptr) {
val = wakeupEngine_->GetParameter(key);
}
return val;
}
void OnlyFirstEngineManager::EngineOnDetected(int32_t uuid)
{
if (wakeupEngine_ != nullptr) {
INTELL_VOICE_LOG_INFO("on engine detected, uuid:%{public}d", uuid);
wakeupEngine_->OnDetected(uuid);
}
}
sptr<IIntellVoiceEngine> OnlyFirstEngineManager::CreateEngineInner(IntellVoiceEngineType type)
{
INTELL_VOICE_LOG_INFO("create engine enter, type: %{public}d", type);
OHOS::IntellVoiceUtils::MemoryGuard memoryGuard;
if (wakeupEngine_ != nullptr) {
return wakeupEngine_;
}
wakeupEngine_ = SptrFactory<EngineBase, OnlyFirstWakeupEngineObj>::CreateInstance();
if (wakeupEngine_ == nullptr) {
INTELL_VOICE_LOG_ERROR("create engine failed, type:%{public}d", type);
return nullptr;
}
INTELL_VOICE_LOG_INFO("create engine ok");
return wakeupEngine_;
}
sptr<IIntellVoiceEngine> OnlyFirstEngineManager::CreateEngine(IntellVoiceEngineType type, const std::string &param)
{
INTELL_VOICE_LOG_INFO("enter, type:%{public}d", type);
if (type != INTELL_VOICE_WAKEUP) {
INTELL_VOICE_LOG_ERROR("invalid type:%{public}d", type);
return nullptr;
}
return CreateEngineInner(type);
}
bool OnlyFirstEngineManager::CreateOrResetWakeupEngine()
{
if (wakeupEngine_ != nullptr) {
INTELL_VOICE_LOG_INFO("wakeup engine is existed");
wakeupEngine_->ReleaseAdapter();
if (!wakeupEngine_->ResetAdapter()) {
INTELL_VOICE_LOG_ERROR("failed to reset adapter");
return false;
}
} else {
if (CreateEngineInner(INTELL_VOICE_WAKEUP) == nullptr) {
INTELL_VOICE_LOG_ERROR("failed to create wakeup engine");
return false;
}
}
return true;
}
int32_t OnlyFirstEngineManager::ReleaseEngineInner(IntellVoiceEngineType type)
{
INTELL_VOICE_LOG_INFO("enter, type:%{public}d", type);
if (type != INTELL_VOICE_WAKEUP) {
INTELL_VOICE_LOG_ERROR("invalid type:%{public}d", type);
return 0;
}
//hap only releases Napi, and does not release sa resources
OHOS::IntellVoiceUtils::MemoryGuard memoryGuard;
if (wakeupEngine_ != nullptr) {
wakeupEngine_->Detach();
wakeupEngine_ = nullptr;
}
return 0;
}
int32_t OnlyFirstEngineManager::ServiceStopProc()
{
INTELL_VOICE_LOG_INFO("enter");
if (wakeupEngine_ != nullptr) {
INTELL_VOICE_LOG_INFO("clear wakeup engine callback");
wakeupEngine_->Detach();
}
return 0;
}
} // namespace IntellVoiceEngine
} // namespace OHOS
@@ -0,0 +1,146 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* 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.
*/
#include "only_first_wakeup_engine.h"
#include "only_first_engine_manager.h"
#include "only_first_wakeup_engine_impl.h"
#include "intell_voice_log.h"
#include "engine_callback_message.h"
#include "intell_voice_util.h"
#define LOG_TAG "OnlyFirstWakeupEngine"
using namespace OHOS::IntellVoiceUtils;
namespace OHOS {
namespace IntellVoiceEngine {
static const std::string SINGLE_WAKEUP_RECORD_START = "record_start";
OnlyFirstWakeupEngine::OnlyFirstWakeupEngine()
{
INTELL_VOICE_LOG_INFO("enter");
}
OnlyFirstWakeupEngine::~OnlyFirstWakeupEngine()
{
INTELL_VOICE_LOG_INFO("enter");
}
int32_t OnlyFirstWakeupEngine::HandleCapturerMsg(StateMsg &msg)
{
return ROLE(OnlyFirstWakeupEngineImpl).Handle(msg);
}
void OnlyFirstWakeupEngine::OnDetected(int32_t uuid)
{
INTELL_VOICE_LOG_INFO("enter, uuid is %{public}d", uuid);
StateMsg msg(START_RECOGNIZE, &uuid, sizeof(int32_t));
if (HandleCapturerMsg(msg) != 0) {
INTELL_VOICE_LOG_WARN("start failed");
EngineCallbackMessage::CallFunc(HANDLE_CLOSE_WAKEUP_SOURCE, true);
}
}
bool OnlyFirstWakeupEngine::Init(const std::string & /* param */, bool reEnroll)
{
StateMsg msg(INIT);
if (HandleCapturerMsg(msg) != 0) {
return false;
}
return true;
}
int32_t OnlyFirstWakeupEngine::StartCapturer(int32_t channels)
{
StateMsg msg(START_CAPTURER, &channels, sizeof(int32_t));
return HandleCapturerMsg(msg);
}
int32_t OnlyFirstWakeupEngine::Read(std::vector<uint8_t> &data)
{
CapturerData capturerData;
StateMsg msg(READ, nullptr, 0, reinterpret_cast<void *>(&capturerData));
int32_t ret = HandleCapturerMsg(msg);
if (ret != 0) {
INTELL_VOICE_LOG_ERROR("read failed, ret:%{public}d", ret);
return -1;
}
data.swap(capturerData.data);
return 0;
}
int32_t OnlyFirstWakeupEngine::StopCapturer()
{
StateMsg msg(STOP_CAPTURER);
return HandleCapturerMsg(msg);
}
int32_t OnlyFirstWakeupEngine::Detach(void)
{
StateMsg msg(RELEASE);
return HandleCapturerMsg(msg);
}
int32_t OnlyFirstWakeupEngine::SetParameter(const std::string &keyValueList)
{
std::map<std::string, std::string> kvpairs;
IntellVoiceUtil::SplitStringToKVPair(keyValueList, kvpairs);
for (auto it : kvpairs) {
if (it.first == SINGLE_WAKEUP_RECORD_START) {
ResetSingleLevelWakeup(it.second);
} else {
INTELL_VOICE_LOG_INFO("no need to process, key:%{public}s, value:%{public}s",
it.first.c_str(), it.second.c_str());
}
}
return 0;
}
std::string OnlyFirstWakeupEngine::GetParameter(const std::string &key)
{
StringParam keyParam(key);
StringParam valueParam;
StateMsg msg(GET_PARAM, &keyParam, sizeof(keyParam), &valueParam);
if (HandleCapturerMsg(msg) != 0) {
INTELL_VOICE_LOG_ERROR("failed to get parameter, key:%{public}s", key.c_str());
return "";
}
return valueParam.strParam;
}
void OnlyFirstWakeupEngine::ReleaseAdapter()
{
StateMsg msg(RELEASE);
HandleCapturerMsg(msg);
}
void OnlyFirstWakeupEngine::ResetSingleLevelWakeup(const std::string &value)
{
int32_t recordStart = -1;
INTELL_VOICE_LOG_INFO("record_start:%{public}s", value.c_str());
if (value != std::string("true") && value != std::string("false")) {
return;
}
recordStart = (value == std::string("true")) ? 1 : 0;
StateMsg msg(RECORD_START, &recordStart, sizeof(int32_t));
HandleCapturerMsg(msg);
}
} // namespace IntellVoiceEngine
} // namespace OHOS
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* 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 ONLY_FIRST_WAKEUP_ENGINE_H
#define ONLY_FIRST_WAKEUP_ENGINE_H
#include <string>
#include "base_macros.h"
#include "engine_base.h"
#include "only_first_wakeup_engine_impl.h"
namespace OHOS {
namespace IntellVoiceEngine {
class OnlyFirstWakeupEngine : public EngineBase {
public:
OnlyFirstWakeupEngine();
~OnlyFirstWakeupEngine();
bool Init(const std::string &param, bool reEnroll = false) override;
void SetCallback(sptr<IRemoteObject> object) override {};
int32_t Attach(const IntellVoiceEngineInfo &info) override {return 0;};
int32_t Detach(void) override;
int32_t Start(bool isLast) override { return 0; };
int32_t SetParameter(const std::string &keyValueList) override;
std::string GetParameter(const std::string &key) override;
int32_t Stop() override { return 0; };
int32_t GetWakeupPcm(std::vector<uint8_t> &data) override { return 0; };
void OnDetected(int32_t uuid) override;
void ReleaseAdapter() override;
int32_t StartCapturer(int32_t channels) override;
int32_t Read(std::vector<uint8_t> &data) override;
int32_t StopCapturer() override;
int32_t NotifyHeadsetWakeEvent() override { return 0; };
int32_t NotifyHeadsetHostEvent(HeadsetHostEventType event) override { return 0; };
private:
void ResetSingleLevelWakeup(const std::string &value);
int32_t HandleCapturerMsg(StateMsg &msg);
USE_ROLE(OnlyFirstWakeupEngineImpl);
};
}
}
#endif
@@ -0,0 +1,332 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* 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.
*/
#include "only_first_wakeup_engine_impl.h"
#include "audio_system_manager.h"
#include "intell_voice_info.h"
#include "intell_voice_log.h"
#include "intell_voice_util.h"
#include "string_util.h"
#include "engine_callback_message.h"
#define LOG_TAG "OnlyFirstWakeupEngineImpl"
using namespace OHOS::IntellVoice;
using namespace OHOS::AudioStandard;
using namespace OHOS::IntellVoiceUtils;
namespace OHOS {
namespace IntellVoiceEngine {
static constexpr uint32_t MIN_BUFFER_SIZE = 640;
static constexpr uint32_t INTERVAL = 96;
static const std::string WAKEUP_SOURCE_CHANNEL = "wakeup_source_channel";
static constexpr int64_t RECOGNIZE_COMPLETE_TIMEOUT_US = 2 * 1000 * 1000; //2s
static constexpr int64_t READ_CAPTURER_TIMEOUT_US = 10 * 1000 * 1000; //10s
OnlyFirstWakeupEngineImpl::OnlyFirstWakeupEngineImpl()
: ModuleStates(State(IDLE), "OnlyFirstWakeupEngineImpl", "WakeupThread")
{
InitStates();
capturerOptions_.streamInfo.samplingRate = AudioSamplingRate::SAMPLE_RATE_16000;
capturerOptions_.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
capturerOptions_.streamInfo.format = AudioSampleFormat::SAMPLE_S16LE;
capturerOptions_.streamInfo.channels = AudioChannel::MONO;
capturerOptions_.capturerInfo.sourceType = SourceType::SOURCE_TYPE_WAKEUP;
capturerOptions_.capturerInfo.capturerFlags = 0;
}
OnlyFirstWakeupEngineImpl::~OnlyFirstWakeupEngineImpl()
{
}
bool OnlyFirstWakeupEngineImpl::InitStates()
{
FromState(IDLE, READ_CAPTURER)
.ACT(GET_PARAM, HandleGetParam);
ForState(IDLE)
.ACT(INIT, HandleInit);
ForState(INITIALIZED)
.ACT(START_RECOGNIZE, HandleStart);
ForState(RECOGNIZED)
.WaitUntil(RECOGNIZE_COMPLETE_TIMEOUT, std::bind(&OnlyFirstWakeupEngineImpl::HandleStopCapturer, this,
std::placeholders::_1, std::placeholders::_2), RECOGNIZE_COMPLETE_TIMEOUT_US)
.ACT(START_CAPTURER, HandleStartCapturer)
.ACT(STOP_CAPTURER, HandleStopCapturer)
.ACT(RECORD_START, HandleRecordStart);
ForState(READ_CAPTURER)
.WaitUntil(READ_CAPTURER_TIMEOUT, std::bind(&OnlyFirstWakeupEngineImpl::HandleStopCapturer, this,
std::placeholders::_1, std::placeholders::_2), READ_CAPTURER_TIMEOUT_US)
.ACT(READ, HandleRead)
.ACT(STOP_CAPTURER, HandleStopCapturer);
FromState(INITIALIZED, READ_CAPTURER)
.ACT(RELEASE, HandleRelease);
return IsStatesInitSucc();
}
int32_t OnlyFirstWakeupEngineImpl::Handle(const StateMsg &msg)
{
if (!IsStatesInitSucc()) {
INTELL_VOICE_LOG_ERROR("failed to init state");
return -1;
}
return ModuleStates::HandleMsg(msg);
}
bool OnlyFirstWakeupEngineImpl::CreateWakeupSourceStopCallback()
{
if (wakeupSourceStopCallback_ != nullptr) {
INTELL_VOICE_LOG_INFO("wakeup close cb is already created");
return true;
}
auto audioSystemManager = AudioSystemManager::GetInstance();
if (audioSystemManager == nullptr) {
INTELL_VOICE_LOG_ERROR("audioSystemManager is nullptr");
return false;
}
wakeupSourceStopCallback_ = std::make_shared<WakeupSourceStopCallback>();
if (wakeupSourceStopCallback_ == nullptr) {
INTELL_VOICE_LOG_ERROR("wakeup source stop callback is nullptr");
return false;
}
audioSystemManager->SetWakeUpSourceCloseCallback(wakeupSourceStopCallback_);
return true;
}
void OnlyFirstWakeupEngineImpl::DestroyWakeupSourceStopCallback()
{
if (wakeupSourceStopCallback_ == nullptr) {
INTELL_VOICE_LOG_INFO("wakeup close cb is already destroyed");
return;
}
auto audioSystemManager = AudioSystemManager::GetInstance();
if (audioSystemManager == nullptr) {
INTELL_VOICE_LOG_ERROR("audioSystemManager is nullptr");
return;
}
audioSystemManager->SetWakeUpSourceCloseCallback(nullptr);
wakeupSourceStopCallback_ = nullptr;
}
bool OnlyFirstWakeupEngineImpl::StartAudioSource()
{
auto listener = std::make_unique<AudioSourceListener>(
[&](uint8_t *buffer, uint32_t size, bool isEnd) {
ReadBufferCallback(buffer, size, isEnd);
},
[&]() {
IntellVoiceUtil::StartAbility("single_level_event");
INTELL_VOICE_LOG_INFO("single_level_event");
});
if (listener == nullptr) {
INTELL_VOICE_LOG_ERROR("create listener failed");
return false;
}
WakeupSourceProcess::Init(capturerOptions_.streamInfo.channels);
audioSource_ = std::make_unique<AudioSource>(MIN_BUFFER_SIZE * static_cast<uint32_t>(
capturerOptions_.streamInfo.channels), INTERVAL, std::move(listener), capturerOptions_);
if (audioSource_ == nullptr) {
INTELL_VOICE_LOG_ERROR("create audio source failed");
WakeupSourceProcess::Release();
return false;
}
if (!audioSource_->Start()) {
INTELL_VOICE_LOG_ERROR("start capturer failed");
audioSource_ = nullptr;
WakeupSourceProcess::Release();
return false;
}
return true;
}
void OnlyFirstWakeupEngineImpl::StopAudioSource()
{
INTELL_VOICE_LOG_INFO("enter");
if (audioSource_ == nullptr) {
INTELL_VOICE_LOG_INFO("audio source is nullptr, no need to stop");
return;
}
audioSource_->Stop();
audioSource_ = nullptr;
WakeupSourceProcess::Release();
}
void OnlyFirstWakeupEngineImpl::OnInitDone(int32_t result)
{
INTELL_VOICE_LOG_INFO("on Init Done, result:%{public}d", result);
StateMsg msg(INIT_DONE, &result, sizeof(int32_t));
Handle(msg);
}
int32_t OnlyFirstWakeupEngineImpl::HandleGetParam(const StateMsg &msg, State & /* nextState */)
{
StringParam *key = reinterpret_cast<StringParam *>(msg.inMsg);
StringParam *value = reinterpret_cast<StringParam *>(msg.outMsg);
if ((key == nullptr) || (value == nullptr)) {
INTELL_VOICE_LOG_INFO("key or value is nullptr");
return -1;
}
if (key->strParam == WAKEUP_SOURCE_CHANNEL) {
value->strParam = std::to_string(static_cast<uint32_t>(capturerOptions_.streamInfo.channels));
} else {
value->strParam = "";
}
INTELL_VOICE_LOG_INFO("key:%{public}s, value:%{public}s", key->strParam.c_str(), value->strParam.c_str());
return 0;
}
int32_t OnlyFirstWakeupEngineImpl::HandleInit(const StateMsg & /* msg */, State &nextState)
{
INTELL_VOICE_LOG_INFO("enter");
nextState = State(INITIALIZED);
return 0;
}
int32_t OnlyFirstWakeupEngineImpl::HandleStart(const StateMsg &msg, State &nextState)
{
int32_t *msgBody = reinterpret_cast<int32_t *>(msg.inMsg);
if (msgBody == nullptr) {
INTELL_VOICE_LOG_ERROR("msgBody is nullptr");
return -1;
}
channelId_ = CHANNEL_ID_0;
INTELL_VOICE_LOG_INFO("enter, channel id is %{public}d", channelId_);
if (!CreateWakeupSourceStopCallback()) {
INTELL_VOICE_LOG_ERROR("create wakeup source stop callback failed");
return -1;
}
if (!StartAudioSource()) {
INTELL_VOICE_LOG_ERROR("start audio source failed");
return -1;
}
INTELL_VOICE_LOG_INFO("exit");
nextState = State(RECOGNIZED);
return 0;
}
int32_t OnlyFirstWakeupEngineImpl::HandleStartCapturer(const StateMsg &msg, State &nextState)
{
INTELL_VOICE_LOG_INFO("enter");
auto ret = IntellVoiceUtil::VerifySystemPermission(OHOS_MICROPHONE_PERMISSION);
if (ret != INTELLIGENT_VOICE_SUCCESS) {
return ret;
}
int32_t *msgBody = reinterpret_cast<int32_t *>(msg.inMsg);
if (msgBody == nullptr) {
INTELL_VOICE_LOG_ERROR("msgBody is nullptr");
return INTELLIGENT_VOICE_START_CAPTURER_FAILED;
}
channels_ = *msgBody;
nextState = State(READ_CAPTURER);
return 0;
}
int32_t OnlyFirstWakeupEngineImpl::HandleRead(const StateMsg &msg, State & /* nextState */)
{
CapturerData *capturerData = reinterpret_cast<CapturerData *>(msg.outMsg);
if (capturerData == nullptr) {
INTELL_VOICE_LOG_ERROR("capturer data is nullptr");
return -1;
}
auto ret = WakeupSourceProcess::Read(capturerData->data, channels_);
if (ret != 0) {
INTELL_VOICE_LOG_ERROR("read capturer data failed");
return ret;
}
ResetTimerDelay();
return 0;
}
int32_t OnlyFirstWakeupEngineImpl::HandleStopCapturer(const StateMsg & /* msg */, State &nextState)
{
INTELL_VOICE_LOG_INFO("enter");
StopAudioSource();
nextState = State(INITIALIZED);
return 0;
}
int32_t OnlyFirstWakeupEngineImpl::HandleRelease(const StateMsg & /* msg */, State &nextState)
{
INTELL_VOICE_LOG_INFO("enter");
DestroyWakeupSourceStopCallback();
StopAudioSource();
nextState = State(IDLE);
return 0;
}
void OnlyFirstWakeupEngineImpl::ReadBufferCallback(uint8_t *buffer, uint32_t size, bool isEnd)
{
std::vector<std::vector<uint8_t>> audioData;
auto ret = IntellVoiceUtil::DeinterleaveAudioData(reinterpret_cast<int16_t *>(buffer),
size / sizeof(int16_t), static_cast<int32_t>(capturerOptions_.streamInfo.channels), audioData);
if ((!ret) || ((audioData.size() != static_cast<uint32_t>(capturerOptions_.streamInfo.channels))) ||
(channelId_ >= audioData.size())) {
INTELL_VOICE_LOG_ERROR("failed to deinterleave, ret:%{public}d, id:%{public}d", ret, channelId_);
return;
}
WakeupSourceProcess::Write(audioData);
}
int32_t OnlyFirstWakeupEngineImpl::HandleRecordStart(const StateMsg &msg, State &nextState)
{
INTELL_VOICE_LOG_INFO("enter");
int32_t *value = reinterpret_cast<int32_t *>(msg.inMsg);
if (value == nullptr) {
INTELL_VOICE_LOG_ERROR("invaid value");
return -1;
}
if ((*value != 0) && (*value != 1)) {
INTELL_VOICE_LOG_ERROR("invaid value %d", *value);
return 0;
}
recordStart_ = *value;
if (recordStart_ == 0) {
StopAudioSource();
}
nextState = State(INITIALIZED);
return 0;
}
}
}
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* 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 ONLY_FIRST_WAKEUP_ENGINE_IMPL_H
#define ONLY_FIRST_WAKEUP_ENGINE_IMPL_H
#include <memory>
#include <string>
#include "i_intell_voice_engine.h"
#include "state_manager.h"
#include "wakeup_source_stop_callback.h"
#include "audio_source.h"
#include "wakeup_source_process.h"
namespace OHOS {
namespace IntellVoiceEngine {
using OHOS::IntellVoiceUtils::StateMsg;
using OHOS::IntellVoiceUtils::State;
enum EngineEvent {
INIT = 0,
INIT_DONE,
START_RECOGNIZE,
START_CAPTURER,
READ,
STOP_CAPTURER,
READ_CAPTURER_TIMEOUT,
GET_PARAM,
RELEASE,
RECOGNIZE_COMPLETE_TIMEOUT,
RECORD_START,
};
struct CapturerData {
std::vector<uint8_t> data;
};
struct StringParam {
explicit StringParam(const std::string &str = "") : strParam(str) {}
std::string strParam;
};
class OnlyFirstWakeupEngineImpl : private OHOS::IntellVoiceUtils::ModuleStates, private WakeupSourceProcess {
public:
OnlyFirstWakeupEngineImpl();
~OnlyFirstWakeupEngineImpl();
int32_t Handle(const StateMsg &msg);
private:
enum EngineState {
IDLE = 0,
INITIALIZED,
RECOGNIZED,
READ_CAPTURER,
};
private:
bool StartAudioSource();
void StopAudioSource();
bool CreateWakeupSourceStopCallback();
void DestroyWakeupSourceStopCallback();
void OnInitDone(int32_t result);
private:
bool InitStates();
int32_t HandleGetParam(const StateMsg &msg, State &nextState);
int32_t HandleInit(const StateMsg &msg, State &nextState);
int32_t HandleStart(const StateMsg &msg, State &nextState);
int32_t HandleStartCapturer(const StateMsg &msg, State &nextState);
int32_t HandleRead(const StateMsg &msg, State &nextState);
int32_t HandleStopCapturer(const StateMsg &msg, State &nextState);
int32_t HandleRelease(const StateMsg &msg, State &nextState);
void ReadBufferCallback(uint8_t *buffer, uint32_t size, bool isEnd);
int32_t HandleRecordStart(const StateMsg &msg, State &nextState);
private:
int32_t channels_ = 0;
uint32_t channelId_ = 0;
std::shared_ptr<WakeupSourceStopCallback> wakeupSourceStopCallback_ = nullptr;
std::unique_ptr<AudioSource> audioSource_ = nullptr;
OHOS::AudioStandard::AudioCapturerOptions capturerOptions_;
int32_t recordStart_ = -1;
};
}
}
#endif
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
* 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 ONLY_FIRST_WAKEUP_ENGINE_OBJ_H
#define ONLY_FIRST_WAKEUP_ENGINE_OBJ_H
#include "base_macros.h"
#include "intell_voice_generic_factory.h"
#include "only_first_wakeup_engine.h"
#include "only_first_wakeup_engine_impl.h"
namespace OHOS {
namespace IntellVoiceEngine {
class OnlyFirstWakeupEngineObj : public OnlyFirstWakeupEngine, public OnlyFirstWakeupEngineImpl {
public:
~OnlyFirstWakeupEngineObj() {}
private:
OnlyFirstWakeupEngineObj() {}
IMPL_ROLE(OnlyFirstWakeupEngineImpl);
friend class IntellVoiceUtils::SptrFactory<EngineBase, OnlyFirstWakeupEngineObj>;
};
}
}
#endif
@@ -20,6 +20,8 @@
#include "headset_wakeup_wrapper.h"
#include "engine_callback_message.h"
#include "intell_voice_util.h"
#include "ability_manager_client.h"
#include "history_info_mgr.h"
#define LOG_TAG "WakeupEngine"
@@ -142,13 +144,38 @@ int32_t WakeupEngine::NotifyHeadsetWakeEvent()
return -1;
}
std::thread([]() { IntellVoiceUtil::StartAbility("headset_event"); }).detach();
std::thread([]() { StartAbility("headset_event"); }).detach();
detectDeviceType_.store(DETECT_TYPE_HEADSET);
StateMsg msg(START_RECOGNIZE);
return headsetImpl_->Handle(msg);
}
void WakeupEngine::StartAbility(const std::string &event)
{
AAFwk::Want want;
HistoryInfoMgr &historyInfoMgr = HistoryInfoMgr::GetInstance();
std::string bundleName = historyInfoMgr.GetStringKVPair(KEY_WAKEUP_ENGINE_BUNDLE_NAME);
std::string abilityName = historyInfoMgr.GetStringKVPair(KEY_WAKEUP_ENGINE_ABILITY_NAME);
INTELL_VOICE_LOG_INFO("bundleName:%{public}s, abilityName:%{public}s", bundleName.c_str(), abilityName.c_str());
if (bundleName.empty() || abilityName.empty()) {
INTELL_VOICE_LOG_ERROR("bundle name is empty or ability name is empty");
return;
}
want.SetElementName(bundleName, abilityName);
want.SetParam("serviceName", std::string("intell_voice"));
want.SetParam("servicePid", getpid());
want.SetParam("eventType", event);
want.SetParam("supportOneShot", true);
auto abilityManagerClient = AAFwk::AbilityManagerClient::GetInstance();
if (abilityManagerClient == nullptr) {
INTELL_VOICE_LOG_ERROR("abilityManagerClient is nullptr");
return;
}
abilityManagerClient->StartAbility(want);
}
int32_t WakeupEngine::HandleHeadsetOff()
{
{
@@ -58,6 +58,7 @@ private:
int32_t HandleHeadsetOff();
int32_t HandleHeadsetOn();
int32_t HandleCapturerMsg(StateMsg &msg);
static void StartAbility(const std::string &event);
USE_ROLE(WakeupEngineImpl);
private:
+4 -1
View File
@@ -65,7 +65,7 @@ ohos_source_set("server_source") {
"ipc:ipc_core",
"kv_store:distributeddata_inner",
"safwk:system_ability_fwk",
"samgr:samgr_proxy",
"samgr:samgr_proxy"
]
sanitize = {
@@ -91,6 +91,9 @@ ohos_source_set("server_source") {
if (intelligent_voice_framework_only_first_stage) {
cflags_cc += [ "-DONLY_FIRST_STAGE" ]
if (intelligent_voice_framework_first_stage_oneshot_enable) {
cflags_cc += [ "-DFIRST_STAGE_ONESHOT_ENABLE" ]
}
}
subsystem_name = "ai"
@@ -45,7 +45,7 @@ template<typename T, typename E>
IntellVoiceServiceManager<T, E>::IntellVoiceServiceManager() : TaskExecutor("ServMgrThread", MAX_TASK_NUM)
{
TaskExecutor::StartThread();
#ifdef ENGINE_ENABLE
#if defined(ENGINE_ENABLE) || defined(FIRST_STAGE_ONESHOT_ENABLE)
RegisterEngineCallbacks();
#endif
#ifdef TRIGGER_ENABLE
@@ -444,7 +444,7 @@ void IntellVoiceServiceManager<T, E>::CreateAndStartServiceObject(int32_t uuid,
return;
}
#ifndef ONLY_FIRST_STAGE
#if defined(ENGINE_ENABLE) || defined(FIRST_STAGE_ONESHOT_ENABLE)
INTELL_VOICE_LOG_INFO("is not single wakeup level");
if (!needResetAdapter) {
E::CreateEngine(INTELL_VOICE_WAKEUP);
@@ -800,7 +800,13 @@ int32_t IntellVoiceServiceManager<T, E>::EngineSetParameter(const std::string &k
historyInfoMgr.SetStringKVPair(KEY_WAKEUP_ENGINE_ABILITY_NAME, it.second);
#ifdef ONLY_FIRST_STAGE
} else if (it.first == std::string("record_start")) {
#ifndef FIRST_STAGE_ONESHOT_ENABLE
ResetSingleLevelWakeup(it.second);
#else
std::string keyValue = it.first;
keyValue.append("=").append(it.second);
E::SetParameter(keyValue);
#endif
#endif
} else {
INTELL_VOICE_LOG_INFO("no need to process, key:%{public}s", it.first.c_str());
@@ -23,11 +23,14 @@
#ifdef ENGINE_ENABLE
#include "intell_voice_engine_manager.h"
#elif defined(FIRST_STAGE_ONESHOT_ENABLE)
#include "only_first_engine_manager.h"
#else
#include "dummy_engine_manager.h"
#include "ffrt_api.h"
#endif
#include "ffrt_api.h"
namespace OHOS {
namespace IntellVoiceEngine {
template<typename T, typename E>
@@ -39,6 +42,8 @@ using TriggerManagerType = OHOS::IntellVoiceTrigger::DummyTriggerManager;
#endif
#ifdef ENGINE_ENABLE
using EngineManagerType = IntellVoiceEngineManager;
#elif defined(FIRST_STAGE_ONESHOT_ENABLE)
using EngineManagerType = OnlyFirstEngineManager;
#else
using EngineManagerType = DummyEngineManager;
#endif