From 859c4b73713579b9d583d3890fa68b99602041b0 Mon Sep 17 00:00:00 2001 From: Charles Date: Sat, 13 Sep 2025 17:41:38 +0800 Subject: [PATCH 1/5] proaudio inject Signed-off-by: Charles --- services/audio_engine/BUILD.gn | 3 + .../manager/include/hpae_capturer_manager.h | 4 + .../manager/include/hpae_manager.h | 5 +- .../manager/include/hpae_manager_impl.h | 2 +- .../include/hpae_virtual_capturer_manager.h | 5 + .../manager/include/i_hpae_capturer_manager.h | 4 + .../manager/include/i_hpae_manager.h | 2 +- .../manager/include/i_hpae_renderer_manager.h | 1 + .../manager/src/hpae_capturer_manager.cpp | 86 +++++-- .../audio_engine/manager/src/hpae_manager.cpp | 91 ++++++- .../manager/src/hpae_manager_impl.cpp | 2 +- .../src/hpae_virtual_capturer_manager.cpp | 14 ++ .../manager/src/i_hpae_renderer_manager.cpp | 10 + .../node/include/hpae_mixer_node.h | 3 + .../node/include/hpae_node_common.h | 2 + .../include/hpae_sink_virtual_output_node.h | 70 ++++++ .../include/hpae_source_process_cluster.h | 9 + .../audio_engine/node/src/hpae_mixer_node.cpp | 26 ++ .../node/src/hpae_node_common.cpp | 14 ++ .../src/hpae_sink_virtual_output_node.cpp | 225 ++++++++++++++++++ .../node/src/hpae_source_process_cluster.cpp | 105 ++++++-- .../unittest/manager/hpae_manager_test.cpp | 99 ++++++++ .../hpaecapturermanager_fuzzer/BUILD.gn | 1 + 23 files changed, 733 insertions(+), 50 deletions(-) create mode 100644 services/audio_engine/node/include/hpae_sink_virtual_output_node.h create mode 100644 services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp diff --git a/services/audio_engine/BUILD.gn b/services/audio_engine/BUILD.gn index d22bf80861..31b461d703 100644 --- a/services/audio_engine/BUILD.gn +++ b/services/audio_engine/BUILD.gn @@ -175,12 +175,14 @@ ohos_shared_library("audio_engine_node") { "node/src/hpae_resample_node.cpp", "node/src/hpae_sink_input_node.cpp", "node/src/hpae_sink_output_node.cpp", + "node/src/hpae_sink_virtual_output_node.cpp", "node/src/hpae_source_input_cluster.cpp", "node/src/hpae_source_input_node.cpp", "node/src/hpae_source_output_node.cpp", "node/src/hpae_source_process_cluster.cpp", "node/src/hpae_remote_sink_output_node.cpp", "node/src/hpae_remote_output_cluster.cpp", + "node/src/hpae_virtual_process_cluster.cpp", ] deps = [ @@ -238,6 +240,7 @@ ohos_shared_library("audio_engine_manager") { "manager/src/i_hpae_manager.cpp", "manager/src/i_hpae_renderer_manager.cpp", "manager/src/hpae_virtual_capturer_manager.cpp", + "manager/src/hpae_injector_renderer_manager.cpp", ] deps = [ diff --git a/services/audio_engine/manager/include/hpae_capturer_manager.h b/services/audio_engine/manager/include/hpae_capturer_manager.h index b1ebd3b9d7..96cae18c02 100644 --- a/services/audio_engine/manager/include/hpae_capturer_manager.h +++ b/services/audio_engine/manager/include/hpae_capturer_manager.h @@ -75,6 +75,10 @@ public: int32_t ReloadCaptureManager(const HpaeSourceInfo &sourceInfo, bool isReload = false) override; int32_t DumpSourceInfo() override; std::string GetDeviceHDFDumpInfo() override; + int32_t AddCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) override; + int32_t RemoveCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) override; private: void SendRequest(Request &&request, const std::string &funcName, bool isInit = false); int32_t CreateOutputSession(const HpaeStreamInfo &streamInfo); diff --git a/services/audio_engine/manager/include/hpae_manager.h b/services/audio_engine/manager/include/hpae_manager.h index 82497ab535..a055370ee5 100644 --- a/services/audio_engine/manager/include/hpae_manager.h +++ b/services/audio_engine/manager/include/hpae_manager.h @@ -201,7 +201,7 @@ public: void RemoveCaptureInjector( const uint32_t &sinkPortIndex, const uint32_t &sourcePortIndex, const SourceType &sourceType) override; int32_t PeekAudioData( - const uint32_t &sinkPortIndex, uint8_t *buffer, size_t bufferSize, AudioStreamInfo &streamInfo) override; + const uint32_t &sinkPortIndex, uint8_t **buffer, size_t bufferSize, AudioStreamInfo &streamInfo) override; private: int32_t CloseOutAudioPort(std::string sinkName); int32_t CloseInAudioPort(std::string sourceName); @@ -294,6 +294,9 @@ private: std::unordered_map> handlers_; std::string effectLiveState_ = ""; std::mutex mutex_; + + std::unordered_map> sinkVirtualOutputNodeMap_; + std::mutex sinkVirtualOutputNodeMapMutex_; }; } // namespace HPAE diff --git a/services/audio_engine/manager/include/hpae_manager_impl.h b/services/audio_engine/manager/include/hpae_manager_impl.h index 45218dd808..0d8b41408e 100644 --- a/services/audio_engine/manager/include/hpae_manager_impl.h +++ b/services/audio_engine/manager/include/hpae_manager_impl.h @@ -147,7 +147,7 @@ public: void RemoveCaptureInjector( const uint32_t &sinkPortIndex, const uint32_t &sourcePortIndex, const SourceType &sourceType) override; int32_t PeekAudioData( - const uint32_t &sinkPortIndex, uint8_t *buffer, size_t bufferSize, AudioStreamInfo &streamInfo) override; + const uint32_t &sinkPortIndex, uint8_t **buffer, size_t bufferSize, AudioStreamInfo &streamInfo) override; private: std::shared_ptr manager_; }; diff --git a/services/audio_engine/manager/include/hpae_virtual_capturer_manager.h b/services/audio_engine/manager/include/hpae_virtual_capturer_manager.h index 738c08b33f..92f648a773 100644 --- a/services/audio_engine/manager/include/hpae_virtual_capturer_manager.h +++ b/services/audio_engine/manager/include/hpae_virtual_capturer_manager.h @@ -65,6 +65,11 @@ public: int32_t DumpSourceInfo() override; std::string GetDeviceHDFDumpInfo() override; + int32_t AddCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) override; + int32_t RemoveCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) override; + private: void SetSessionState(HpaeCaptureMoveInfo &streamInfo, HpaeSessionState capturerState); diff --git a/services/audio_engine/manager/include/i_hpae_capturer_manager.h b/services/audio_engine/manager/include/i_hpae_capturer_manager.h index 25346dc76f..81efb0be96 100644 --- a/services/audio_engine/manager/include/i_hpae_capturer_manager.h +++ b/services/audio_engine/manager/include/i_hpae_capturer_manager.h @@ -60,6 +60,10 @@ public: virtual void UploadDumpSourceInfo(std::string &deviceName); virtual void OnNotifyDfxNodeInfo(bool isConnect, uint32_t preNodeId, HpaeDfxNodeInfo &nodeInfo); virtual std::string GetDeviceHDFDumpInfo() = 0; + virtual int32_t AddCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) = 0; + virtual int32_t RemoveCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) = 0; private: #ifdef ENABLE_HIDUMP_DFX HpaeDfxTree dfxTree_; diff --git a/services/audio_engine/manager/include/i_hpae_manager.h b/services/audio_engine/manager/include/i_hpae_manager.h index 3f1872f329..19b3ae4ccd 100644 --- a/services/audio_engine/manager/include/i_hpae_manager.h +++ b/services/audio_engine/manager/include/i_hpae_manager.h @@ -151,7 +151,7 @@ public: virtual void RemoveCaptureInjector( const uint32_t &sinkPortIndex, const uint32_t &sourcePortIndex, const SourceType &sourceType) = 0; virtual int32_t PeekAudioData( - const uint32_t &sinkPortIndex, uint8_t *buffer, size_t bufferSize, AudioStreamInfo &streamInfo) = 0; + const uint32_t &sinkPortIndex, uint8_t **buffer, size_t bufferSize, AudioStreamInfo &streamInfo) = 0; }; } // namespace HPAE } // namespace AudioStandard diff --git a/services/audio_engine/manager/include/i_hpae_renderer_manager.h b/services/audio_engine/manager/include/i_hpae_renderer_manager.h index d0a4382050..99d78b886e 100644 --- a/services/audio_engine/manager/include/i_hpae_renderer_manager.h +++ b/services/audio_engine/manager/include/i_hpae_renderer_manager.h @@ -108,6 +108,7 @@ public: virtual int32_t ConnectCoBufferNode(const std::shared_ptr &coBufferNode) {return 0;}; virtual int32_t DisConnectCoBufferNode(const std::shared_ptr &coBufferNode) {return 0;}; virtual std::string GetDeviceHDFDumpInfo() = 0; + virtual int32_t SetSinkVirtualOutputNode(const std::shared_ptr &sinkVirtualOutputNode); private: #ifdef ENABLE_HIDUMP_DFX diff --git a/services/audio_engine/manager/src/hpae_capturer_manager.cpp b/services/audio_engine/manager/src/hpae_capturer_manager.cpp index 55bf50350d..26f1281e05 100644 --- a/services/audio_engine/manager/src/hpae_capturer_manager.cpp +++ b/services/audio_engine/manager/src/hpae_capturer_manager.cpp @@ -106,7 +106,9 @@ int32_t HpaeCapturerManager::CreateOutputSession(const HpaeStreamInfo &streamInf // todo: algorithm instance count control sceneClusterMap_[sceneType] = std::make_shared(nodeInfo); if (CaptureEffectCreate(sceneType, enhanceScene) != SUCCESS) { - sceneClusterMap_.erase(sceneType); + // sceneClusterMap_.erase(sceneType); + // not erase effect processcluster for inject + AUDIO_WARNING_LOG("sceneType[%{public}u] create failed, not delete sceneCluster", sceneType); } } @@ -125,27 +127,30 @@ int32_t HpaeCapturerManager::CaptureEffectRelease(const HpaeProcessorType &scene void HpaeCapturerManager::DisConnectSceneClusterFromSourceInputCluster(HpaeProcessorType &sceneType) { - CHECK_AND_RETURN_LOG(SafeGetMap(sceneClusterMap_, sceneType), "connot find sceneType:%{public}u", sceneType); - CHECK_AND_RETURN_LOG(sceneClusterMap_[sceneType]->GetOutputPortNum() == 0, + auto sceneCluster = SafeGetMap(sceneClusterMap_, sceneType); + CHECK_AND_RETURN_LOG(sceneCluster != nullptr, "connot find sceneType:%{public}u", sceneType); + CHECK_AND_RETURN_LOG(sceneCluster->GetOutputPortNum() == 0, "sceneType:%{public}u outputNum:%{public}u", - sceneType, static_cast(sceneClusterMap_[sceneType]->GetOutputPortNum())); + sceneType, static_cast(sceneCluster->GetOutputPortNum())); // need to disconnect sceneCluster and sourceInputCluster - HpaeNodeInfo ecNodeInfo; - HpaeSourceInputNodeType ecNodeType; - if (CheckEcCondition(sceneType, ecNodeInfo, ecNodeType)) { - sceneClusterMap_[sceneType]->DisConnectWithInfo(sourceInputClusterMap_[ecNodeType], ecNodeInfo); // ec - } + if (sceneCluster->IsEffectNodeValid()) { + HpaeNodeInfo ecNodeInfo; + HpaeSourceInputNodeType ecNodeType; + if (CheckEcCondition(sceneType, ecNodeInfo, ecNodeType)) { + sceneCluster->DisConnectWithInfo(sourceInputClusterMap_[ecNodeType], ecNodeInfo); // ec + } - HpaeNodeInfo micRefNodeInfo; - if (CheckMicRefCondition(sceneType, micRefNodeInfo)) { - // micref - sceneClusterMap_[sceneType]->DisConnectWithInfo(sourceInputClusterMap_[HPAE_SOURCE_MICREF], micRefNodeInfo); + HpaeNodeInfo micRefNodeInfo; + if (CheckMicRefCondition(sceneType, micRefNodeInfo)) { + // micref + sceneCluster->DisConnectWithInfo(sourceInputClusterMap_[HPAE_SOURCE_MICREF], micRefNodeInfo); + } } HpaeNodeInfo micNodeInfo; if (SafeGetMap(sourceInputClusterMap_, mainMicType_) && - sceneClusterMap_[sceneType]->GetCapturerEffectConfig(micNodeInfo, HPAE_SOURCE_BUFFER_TYPE_MIC)) { - sceneClusterMap_[sceneType]->DisConnectWithInfo( + sceneCluster->GetCapturerEffectConfig(micNodeInfo, HPAE_SOURCE_BUFFER_TYPE_MIC)) { + sceneCluster->DisConnectWithInfo( sourceInputClusterMap_[mainMicType_], micNodeInfo); // mic } return; @@ -264,26 +269,29 @@ void HpaeCapturerManager::ConnectProcessClusterWithMicRef(HpaeProcessorType &sce int32_t HpaeCapturerManager::ConnectOutputSession(uint32_t sessionId) { - CHECK_AND_RETURN_RET_LOG(SafeGetMap(sourceOutputNodeMap_, sessionId), ERR_INVALID_PARAM, + auto sourceOutputNode = SafeGetMap(sourceOutputNodeMap_, sessionId); + CHECK_AND_RETURN_RET_LOG(sourceOutputNode, ERR_INVALID_PARAM, "ConnectOutputSession error, sessionId %{public}u can not find in sourceOutputNodeMap.\n", sessionId); HpaeProcessorType sceneType = sessionNodeMap_[sessionId].sceneType; - if (sceneType != HPAE_SCENE_EFFECT_NONE && SafeGetMap(sceneClusterMap_, sceneType)) { + auto scnenCluster = SafeGetMap(sceneClusterMap_, sceneType); + if (sceneType != HPAE_SCENE_EFFECT_NONE && scnenCluster != nullptr) { HpaeNodeInfo micNodeInfo; - if (sceneClusterMap_[sceneType]->GetCapturerEffectConfig(micNodeInfo, HPAE_SOURCE_BUFFER_TYPE_MIC)) { - sceneClusterMap_[sceneType]->ConnectWithInfo(sourceInputClusterMap_[mainMicType_], micNodeInfo); // mic + if (scnenCluster->GetCapturerEffectConfig(micNodeInfo, HPAE_SOURCE_BUFFER_TYPE_MIC)) { + scnenCluster->ConnectWithInfo(sourceInputClusterMap_[mainMicType_], micNodeInfo); // mic + } + if (scnenCluster->IsEffectNodeValid()) { + ConnectProcessClusterWithEc(sceneType); + ConnectProcessClusterWithMicRef(sceneType); } - ConnectProcessClusterWithEc(sceneType); - ConnectProcessClusterWithMicRef(sceneType); - // 1. Determine if the ResampleNode needs to be created // 2. If ResampleNode needs to be created, it should be connected to the UpEffectNode after creation // 3. Connect the SourceOutputNode to the ResampleNode - sourceOutputNodeMap_[sessionId]->ConnectWithInfo(sceneClusterMap_[sceneType], - sourceOutputNodeMap_[sessionId]->GetNodeInfo()); + sourceOutputNode->ConnectWithInfo(scnenCluster, + sourceOutputNode->GetNodeInfo()); } else { - sourceOutputNodeMap_[sessionId]->ConnectWithInfo(sourceInputClusterMap_[mainMicType_], - sourceOutputNodeMap_[sessionId]->GetNodeInfo()); + sourceOutputNode->ConnectWithInfo(sourceInputClusterMap_[mainMicType_], + sourceOutputNode->GetNodeInfo()); } return SUCCESS; } @@ -1013,6 +1021,32 @@ std::string HpaeCapturerManager::GetDeviceHDFDumpInfo() TransDeviceInfoToString(sourceInfo_, config); return config; } + +int32_t HpaeCapturerManager::AddCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) +{ + auto request = [this, sinkOutputNode, sourceType] { + HpaeProcessorType sceneType = TransSourceTypeToSceneType(sourceType); + auto sceneCluster = SaftGetMap(sceneClusterMap_, sceneType); + CHECK_AND_RETURN_LOG(sceneCluster != nullptr, "sourceType[%{public}d] cluster not exit", sourceType); + sceneCluster->ConnectInjector(sinkOutputNode); + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeCapturerManager::RemoveCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) +{ + auto request = [this, sinkOutputNode, sourceType] { + HpaeProcessorType sceneType = TransSourceTypeToSceneType(sourceType); + auto sceneCluster = SaftGetMap(sceneClusterMap_, sceneType); + CHECK_AND_RETURN_LOG(sceneCluster != nullptr, "sourceType[%{public}d] cluster not exit", sourceType); + sceneCluster->DisConnectInjector(sinkOutputNode); + }; + SendRequest(request, __func__); + return SUCCESS; +} } // namespace HPAE } // namespace AudioStandard } // namespace OHOS \ No newline at end of file diff --git a/services/audio_engine/manager/src/hpae_manager.cpp b/services/audio_engine/manager/src/hpae_manager.cpp index 9f88e53c5f..309ab5f724 100644 --- a/services/audio_engine/manager/src/hpae_manager.cpp +++ b/services/audio_engine/manager/src/hpae_manager.cpp @@ -253,6 +253,7 @@ int32_t HpaeManager::ReloadRenderManager(const AudioModuleInfo &audioModuleInfo, { HpaeSinkInfo sinkInfo; sinkInfo.sinkId = sinkNameSinkIdMap_[audioModuleInfo.name]; + uint32_t oldId = sinkInfo.sinkId; int32_t ret = TransModuleInfoToHpaeSinkInfo(audioModuleInfo, sinkInfo); if (ret != SUCCESS) { OnCallbackOpenOrReloadFailed(isReload); @@ -266,6 +267,14 @@ int32_t HpaeManager::ReloadRenderManager(const AudioModuleInfo &audioModuleInfo, sinkIdSinkNameMap_[sinkSourceIndex] = audioModuleInfo.name; sinkNameSinkIdMap_[audioModuleInfo.name] = sinkSourceIndex; } + + if (sinkInfo.deviceName == "virtual") { // todo : rewrite correct name + std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); + sinkVirtualOutputNodeMap_[sinkInfo.sinkId] = sinkVirtualOutputNodeMap_[oldId]; + HpaeNodeInfo nodeInfo; + TransSinkInfoToNodeInfo(sinkInfo, rendererManagerMap_[audioModuleInfo.name], nodeInfo); + sinkVirtualOutputNodeMap_[sinInfo.sinkId]->ReloadNode(nodeInfo); + } rendererManagerMap_[audioModuleInfo.name]->ReloadRenderManager(sinkInfo, isReload); return SUCCESS; } @@ -291,6 +300,14 @@ int32_t HpaeManager::CreateRendererManager(const AudioModuleInfo &audioModuleInf coreSink_ = audioModuleInfo.name; AUDIO_INFO_LOG("SetDefaultSink name: %{public}s", defaultSink_.c_str()); } + + if (sinkInfo.deviceName == "virtual") { // todo : rewrite correct name + std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); + HpaeNodeInfo nodeInfo; + TransSinkInfoToNodeInfo(sinkInfo, rendererManager, nodeInfo); + sinkVirtualOutputNodeMap_[sinkSourceIndex] = std::make_shared(nodeInfo); + rendererManager->SetSinkVirtualOutputNode(sinkVirtualOutputNodeMap_[sinkSourceIndex]); + } rendererManager->Init(isReload); AUDIO_INFO_LOG( "open sink name: %{public}s end sinkIndex is %{public}u", audioModuleInfo.name.c_str(), sinkSourceIndex); @@ -579,6 +596,10 @@ void HpaeManager::AddPreferSinkForDefaultChange(bool isAdd, const std::string &s int32_t HpaeManager::CloseOutAudioPort(std::string sinkName) { + std::unique_lock lock(sinkVirtualOutputNodeMapMutex_, std::defer_lock); + if (sinkName == "virtual") { + lock.lock(); + } if (!SafeGetMap(rendererManagerMap_, sinkName)) { AUDIO_WARNING_LOG("can not find sinkName: %{public}s in rendererManagerMap_", sinkName.c_str()); return SUCCESS; @@ -596,6 +617,9 @@ int32_t HpaeManager::CloseOutAudioPort(std::string sinkName) AddPreferSinkForDefaultChange(isChangeDefaultSink, sinkName); rendererManagerMap_[sinkName]->DeInit(sinkName != defaultSink_); if (sinkName != defaultSink_) { + if (sinkName == "virtual") { + sinkVirtualOutputNodeMap_.erase(sinkNameSinkIdMap_[sinkName]); + } rendererManagerMap_.erase(sinkName); sinkIdSinkNameMap_.erase(sinkNameSinkIdMap_[sinkName]); sinkNameSinkIdMap_.erase(sinkName); @@ -2534,20 +2558,77 @@ void HpaeManager::DeleteStreamVolumeToEffect(const std::string stringSessionID) // interfaces for injector void HpaeManager::UpdateAudioPortInfo(const uint32_t &sinkPortIndex, const AudioModuleInfo &audioPortInfo) -{} +{ + auto request = [this, sinkPortIndex, audioPortInfo] { + CHECK_AND_RETURN_LOG(sinkIdSinkNameMap_.find(sinkPortIndex) != sinkIdSinkNameMap_.end(), + "sinkPortIndex[%{public}u] not exit", sinkPortIndex); + std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); + auto rendererManager = SaftGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); + CHECK_AND_RETURN_LOG(rendererManager, "sink[%{public}s] is in wrong state", + sinkIdSinkNameMap_[sinkPortIndex].c_str()); + HpaeSinkInfo sinkInfo; + int32_t ret = TransModuleInfoToHpaeSinkInfo(audioPortInfo, sinkInfo); + if (ret != SUCCESS) { + return; + } + auto sinkOutputNode = SafeGetMap(sinkVirtualOutputNodeMap_, sinkPortIndex); + CHECK_AND_RETURN_LOG(sinkOutputNode, "reload injector failed, sinkOutputNode is null"); + HpaeNodeInfo nodeInfo; + TransSinkInfoToNodeInfo(sinkInfo, rendererMnaager, nodeInfo); + sinkOutputNode->ReloadNode(nodeInfo); + rendererManager->ReloadRenderManager(sinkInfo, true); + }; + SendRequest(request, __func__); +} void HpaeManager::AddCaptureInjector( const uint32_t &sinkPortIndex, const uint32_t &sourcePortIndex, const SourceType &sourceType) -{} +{ + auto request = [this, sinkPortIndex, sourcePortIndex, sourceType] { + CHECK_AND_RETURN_LOG(sinkIdSinkNameMap_.find(sinkPortIndex) != sinkIdSinkNameMap_.end(), + "sinkPortIndex[%{public}u] not exit", sinkPortIndex); + std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); + auto rendererManager = SaftGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); + CHECK_AND_RETURN_LOG(rendererManager, "sink[%{public}s] is in wrong state", + sinkIdSinkNameMap_[sinkPortIndex].c_str()); + CHECK_AND_RETURN_LOG(sourceIdSourceNameMap_.find(sourcePortIndex) != sourceIdSourceNameMap_.end(), + "sourcePortIndex[%{public}u] not exit", sourcePortIndex); + auto capturerManager = SafeGetMap(sourceIdSourceNameMap_, sourceIdSourceNameMap_[sourcePortIndex]); + CHECK_AND_RETURN_LOG(rendererManager, "source[%{public}s] is in wrong state", + sourceIdSourceNameMap_[sourcePortIndex].c_str()); + capturerManager->AddCaptureInjector(sinkVirtualOutputNodeMap_[sinkPortIndex], sourceType); + }; + SendRequest(request, __func__); +} void HpaeManager::RemoveCaptureInjector( const uint32_t &sinkPortIndex, const uint32_t &sourcePortIndex, const SourceType &sourceType) -{} +{ + auto request = [this, sinkPortIndex, sourcePortIndex, sourceType] { + CHECK_AND_RETURN_LOG(sinkIdSinkNameMap_.find(sinkPortIndex) != sinkIdSinkNameMap_.end(), + "sinkPortIndex[%{public}u] not exit", sinkPortIndex); + std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); + auto rendererManager = SaftGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); + CHECK_AND_RETURN_LOG(rendererManager, "sink[%{public}s] is in wrong state", + sinkIdSinkNameMap_[sinkPortIndex].c_str()); + CHECK_AND_RETURN_LOG(sourceIdSourceNameMap_.find(sourcePortIndex) != sourceIdSourceNameMap_.end(), + "sourcePortIndex[%{public}u] not exit", sourcePortIndex); + auto capturerManager = SafeGetMap(sourceIdSourceNameMap_, sourceIdSourceNameMap_[sourcePortIndex]); + CHECK_AND_RETURN_LOG(rendererManager, "source[%{public}s] is in wrong state", + sourceIdSourceNameMap_[sourcePortIndex].c_str()); + capturerManager->RemoveCaptureInjector(sinkVirtualOutputNodeMap_[sinkPortIndex], sourceType); + }; + SendRequest(request, __func__); +} int32_t HpaeManager::PeekAudioData( - const uint32_t &sinkPortIndex, uint8_t *buffer, size_t bufferSize, AudioStreamInfo &streamInfo) + const uint32_t &sinkPortIndex, uint8_t **buffer, size_t bufferSize, AudioStreamInfo &streamInfo) { - return SUCCESS; + std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); + auto sinkVirtualOutputNode = SafeGetMap(sinkVirtualOutputNodeMap_, sinkPortIndex); + CHECK_AND_RETURN_RET_LOG(sinkVirtualOutputNode != nullptr, ERROR_INVALID_PARAM, + "sinkPort[%{public}u] not exit", sinkPortIndex); + return sinkVirtualOutputNode->PeekAudioData(buffer, bufferSize, audioStreamInfo); } } // namespace HPAE } // namespace AudioStandard diff --git a/services/audio_engine/manager/src/hpae_manager_impl.cpp b/services/audio_engine/manager/src/hpae_manager_impl.cpp index 8e4b271c78..6715f0785f 100644 --- a/services/audio_engine/manager/src/hpae_manager_impl.cpp +++ b/services/audio_engine/manager/src/hpae_manager_impl.cpp @@ -611,7 +611,7 @@ void HpaeManagerImpl::RemoveCaptureInjector( } int32_t HpaeManagerImpl::PeekAudioData( - const uint32_t &sinkPortIndex, uint8_t *buffer, size_t bufferSize, AudioStreamInfo &streamInfo) + const uint32_t &sinkPortIndex, uint8_t **buffer, size_t bufferSize, AudioStreamInfo &streamInfo) { CHECK_AND_RETURN_RET_LOG(manager_, ERR_ILLEGAL_STATE, "manager is nullptr"); return manager_->PeekAudioData(sinkPortIndex, buffer, bufferSize, streamInfo); diff --git a/services/audio_engine/manager/src/hpae_virtual_capturer_manager.cpp b/services/audio_engine/manager/src/hpae_virtual_capturer_manager.cpp index d75b200798..a5ce5c63c6 100644 --- a/services/audio_engine/manager/src/hpae_virtual_capturer_manager.cpp +++ b/services/audio_engine/manager/src/hpae_virtual_capturer_manager.cpp @@ -321,6 +321,20 @@ void HpaeVirtualCapturerManager::SetSessionState(HpaeCaptureMoveInfo &streamInfo CHECK_AND_RETURN_LOG(streamInfo.sourceOutputNode, "streamInfo.sourceOutputNode is nullptr"); streamInfo.sourceOutputNode->SetState(capturerState); } + +int32_t HpaeCapturerManager::AddCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeCapturerManager::RemoveCaptureInjector(const std::shared_ptr> &sinkOutputNode, + const SourceType &sourceType) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} } // namespace HPAE } // namespace AudioStandard } // namespace OHOS \ No newline at end of file diff --git a/services/audio_engine/manager/src/i_hpae_renderer_manager.cpp b/services/audio_engine/manager/src/i_hpae_renderer_manager.cpp index edadb35d57..ce8ff49eff 100644 --- a/services/audio_engine/manager/src/i_hpae_renderer_manager.cpp +++ b/services/audio_engine/manager/src/i_hpae_renderer_manager.cpp @@ -20,6 +20,7 @@ #include "hpae_renderer_manager.h" #include "hpae_offload_renderer_manager.h" #include "hpae_inner_capturer_manager.h" +#include "hpae_injector_renderer_manager.h" #include "audio_engine_log.h" namespace OHOS { @@ -36,6 +37,8 @@ std::shared_ptr IHpaeRendererManager::CreateRendererManage } else if ((sinkInfo.deviceName.compare(0, DEVICE_NAME_INNER_CAP.length(), DEVICE_NAME_INNER_CAP) == 0) || sinkInfo.deviceName == DEVICE_NAME_CAST_INNER_CAP) { return std::make_shared(sinkInfo); + } else if (sinkInfo.deviceName == "virtual") { // todo : rewrite device name + return std::make_shared(sinkInfo); } return std::make_shared(sinkInfo); } @@ -64,6 +67,13 @@ void IHpaeRendererManager::OnNotifyDfxNodeInfo(bool isConnect, uint32_t preNodeI } #endif }; + +int32_t IHpaeRendererManager::SetSinkVirtualOutputNode( + const std::shared_ptr &sinkVirtualOutputNode) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return ERROR; +}; } // namespace HPAE } // namespace AudioStandard } // namespace OHOS diff --git a/services/audio_engine/node/include/hpae_mixer_node.h b/services/audio_engine/node/include/hpae_mixer_node.h index 15f892f885..39d4395301 100644 --- a/services/audio_engine/node/include/hpae_mixer_node.h +++ b/services/audio_engine/node/include/hpae_mixer_node.h @@ -32,6 +32,9 @@ public: int32_t SetupAudioLimiter(); int32_t InitAudioLimiter(); virtual void SetNodeInfo(HpaeNodeInfo& nodeInfo) override; + void ConnectWithInfo(const std::shared_ptr> &preNode, HpaeNodeInfo &nodeInfo) override; + void DisConnectWithInfo(const std::shared_ptr> &preNode, + HpaeNodeInfo &nodeInfo) override; protected: HpaePcmBuffer *SignalProcess(const std::vector &inputs) override; private: diff --git a/services/audio_engine/node/include/hpae_node_common.h b/services/audio_engine/node/include/hpae_node_common.h index f02e3e809c..380b95fa0b 100644 --- a/services/audio_engine/node/include/hpae_node_common.h +++ b/services/audio_engine/node/include/hpae_node_common.h @@ -66,6 +66,8 @@ int32_t TransDeviceInfoToString(const T& info, std::string &config) } void TransStreamInfoToStreamDumpInfo(const std::unordered_map &streamInfoMap, std::vector &dumpInfo); +void TransSinkInfoToNodeInfo(const HpaeSinkInfo &sinkInfo, const std::weak_ptr &statusCallback, + HpaeNodeInfo &nodeInfo); } // namespace HPAE } // namespace AudioStandard } // namespace OHOS diff --git a/services/audio_engine/node/include/hpae_sink_virtual_output_node.h b/services/audio_engine/node/include/hpae_sink_virtual_output_node.h new file mode 100644 index 0000000000..da03d6c3c9 --- /dev/null +++ b/services/audio_engine/node/include/hpae_sink_virtual_output_node.h @@ -0,0 +1,70 @@ +/* + * 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 HPAE_SINK_VIRTUAL_INPUT_NODE_H +#define HPAE_SINK_VIRTUAL_INPUT_NODE_H +#include +#include "audio_info.h" +#include "audio_stream_info.h" +#include "audio_ring_cache.h" +#include "hpae_node.h" +#include "hpae_pcm_buffer.h" + +namespace OHOS { +namespace AudioStandard { +namespace HPAE { +class HpaeSinkVirtualOutputNode : public OutputNode, public InputNode { +public: + HpaeSinkVirtualOutputNode(HpaeNodeInfo &nodeInfo); + virtual ~HpaeSinkVirtualOutputNode(); + void DoRenderProcess(); + void DoProcess() override; + bool Reset() override; + bool ResetAll() override; + + std::shared_ptr GetSharedInstance() override; + OutputPort *GetOutputPort() override; + void Connect(const std::shared_ptr> &preNode) override; + void DisConnect(const std::shared_ptr> &preNode) override; + + StreamManagerState GetState(); + int32_t RenderSinkInit(); + int32_t RenderSinkDeInit(); + int32_t RenderSinkPause(void); + int32_t RenderSinkStart(void); + int32_t RenderSinkStop(void); + size_t GetPreOutNum(); + int32_t SetSinkState(StreamManagerState sinkState); + uint32_t GetLatency(); + bool GetIsReadFinished(); + int32_t PeekAudioData(uint8_t **buffer, const size_t &bufferSize, AudioStreamInfo &audioStreamInfo); + int32_t ReloadNode(hpaeNodeInfo nodeInfo); +private: + size_t GetRingCacheSize(); +private: + InputPort inputStream_; + OutputPort outputStream_; + std::vector renderFrameData_; + PcmBufferInfo pcmBufferInfo_; + std::unique_ptr ringCache_ = nullptr; + HpaePcmBuffer outputAudioBuffer_; + std::mutex mutex_; + StreamManagerState state_ = STREAM_MANAGER_NEW; +}; +} // namespace HPAE +} // namespace AudioStandard +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/audio_engine/node/include/hpae_source_process_cluster.h b/services/audio_engine/node/include/hpae_source_process_cluster.h index ce71ae7ad5..b26390e253 100644 --- a/services/audio_engine/node/include/hpae_source_process_cluster.h +++ b/services/audio_engine/node/include/hpae_source_process_cluster.h @@ -17,6 +17,7 @@ #define HPAE_SOURCE_PROCESS_CLUSTER_H #include "hpae_capture_effect_node.h" #include "hpae_audio_format_converter_node.h" +#include "hpae_mixer_node.h" namespace OHOS { namespace AudioStandard { @@ -39,11 +40,16 @@ public: void ConnectWithInfo(const std::shared_ptr>& preNode, HpaeNodeInfo &nodeInfo) override; void DisConnectWithInfo(const std::shared_ptr>& preNode, HpaeNodeInfo &nodeInfo) override; + // connect injector + void ConnectInjector(const std::shared_ptr>& preNode); + void DisConnectInjector(const std::shared_ptr>& preNode); + bool GetCapturerEffectConfig(HpaeNodeInfo& nodeInfo, HpaeSourceBufferType type = HPAE_SOURCE_BUFFER_TYPE_MIC); size_t GetOutputPortNum(); int32_t CaptureEffectCreate(uint64_t sceneKeyCode, CaptureEffectAttr attr); int32_t CaptureEffectRelease(uint64_t sceneKeyCode); + bool IsEffectNodeValid(); // for ut test uint32_t GetCapturerEffectNodeUseCount(); @@ -51,7 +57,10 @@ public: size_t GetPreOutNum(); private: std::shared_ptr captureEffectNode_; + std::shared_ptr mixerNode_; std::unordered_map> fmtConverterNodeMap_; + std::unordered_map>, + std::shared_ptr> injectorFmtConverterNodeMap_; }; } // namespace HPAE } // namespace AudioStandard diff --git a/services/audio_engine/node/src/hpae_mixer_node.cpp b/services/audio_engine/node/src/hpae_mixer_node.cpp index 16b2dbdb2f..5bd640b15c 100644 --- a/services/audio_engine/node/src/hpae_mixer_node.cpp +++ b/services/audio_engine/node/src/hpae_mixer_node.cpp @@ -66,6 +66,32 @@ void HpaeMixerNode::SetNodeInfo(HpaeNodeInfo& nodeInfo) HpaeNode::SetNodeInfo(nodeInfo); } +void HpaeCaptureEffectNode::ConnectWithInfo(const std::shared_ptr> &preNode, + HpaeNodeInfo &nodeInfo) +{ + std::shared_ptr realPreNode = preNode->GetSharedInstance(nodeInfo); + CHECK_AND_RETURN_LOG(realPreNode != nullptr, "realPreNode is nullptr"); + inputStream_.Connect(realPreNode, preNode->GetOutputPort(nodeInfo)); +#ifdef ENABLE_HIDUMP_DFX + if (auto callback = GetNodeStatusCallback().lock()) { + callback->OnNotifyDfxNodeInfo(true, realPreNode->GetNodeId(), GetNodeInfo()); + } +#endif +} + +void HpaeCaptureEffectNode::DisConnectWithInfo(const std::shared_ptr>& preNode, + HpaeNodeInfo &nodeInfo) +{ + CHECK_AND_RETURN_LOG(!inputStream_.CheckIfDisConnected(preNode->GetOutputPort(nodeInfo)), + "HpaeMixerNode[%{public}u] has disconnected with preNode", GetNodeId()); + inputStream_.DisConnect(preNode->GetOutputPort(nodeInfo, true)); +#ifdef ENABLE_HIDUMP_DFX + if (auto callback = GetNodeStatusCallback().lock()) { + callback->OnNotifyDfxNodeInfo(false, GetNodeId(), GetNodeInfo()); + } +#endif +} + int32_t HpaeMixerNode::SetupAudioLimiter() { if (limiter_ != nullptr) { diff --git a/services/audio_engine/node/src/hpae_node_common.cpp b/services/audio_engine/node/src/hpae_node_common.cpp index fbb39f815a..46e5ee3c0d 100644 --- a/services/audio_engine/node/src/hpae_node_common.cpp +++ b/services/audio_engine/node/src/hpae_node_common.cpp @@ -526,6 +526,20 @@ int32_t CheckSourceInfoFramelen(const HpaeSourceInfo &sourceInfo) } return SUCCESS; } + +void TransSinkInfoToNodeInfo(const HpaeSinkInfo &sinkInfo, const std::weak_ptr &statusCallback, + HpaeNodeInfo &nodeInfo) +{ + nodeInfo.channels = sinkInfo_.channels; + nodeInfo.format = sinkInfo_.format; + nodeInfo.frameLen = sinkInfo_.frameLen; + nodeInfo.nodeId = 0; + nodeInfo.samplingRate = sinkInfo_.samplingRate; + nodeInfo.sceneType = HPAE_SCENE_EFFECT_OUT; + nodeInfo.deviceNetId = sinkInfo_.deviceNetId; + nodeInfo.deviceClass = sinkInfo_.deviceClass; + nodeInfo.statusCallback = statusCallback; +} } // namespace HPAE } // namespace AudioStandard } // namespace OHOS \ No newline at end of file diff --git a/services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp b/services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp new file mode 100644 index 0000000000..722bf9afa9 --- /dev/null +++ b/services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp @@ -0,0 +1,225 @@ +/* + * 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 LOG_TAG +#define LOG_TAG "HpaeSinkVirtualOutputNode" +#endif + +#include "hpae_sink_virtual_output_node.h" +#include "audio_common_utils.h" +#include "audio_errors.h" +#include "audio_utils.h" +#include "hpae_format_convert.h" +#include "hpae_node_common.h" +#include "audio_engine_log.h" + +namespace OHOS { +namespace AudioStandard { +namespace HPAE { +static constexpr uint32_t DEFAULT_RING_CACHE_NUM = 1; +static constexpr uint32_t DEFAULT_FRAME_LEN_MS = 20; +static constexpr uint32_t MS_PER_SECOND = 1000; + +HpaeSinkVirtualOutputNode::HpaeSinkVirtualOutputNode(HpaeNodeInfo &nodeInfo) + : HpaeNode(nodeInfo), outputStream_(this), + renderFrameData_(nodeInfo.frameLen * nodeInfo.channels * GetSizeFromFormat(nodeInfo.format)), + pcmBufferInfo_(nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate), + outputAudioBuffer_(pcmBufferInfo_) +{ +#ifdef ENABLE_HIDUMP_DFX + SetNodeName("HpaeSinkVirtualOutputNode"); + if (auto callback = GetNodeStatusCallback().lock()) { + callback->OnNotifyDfxNodeInfo(true, 0, GetNodeInfo()); + } +#endif + ringCache_ = AudioRingCache::Create(GetRingCacheSize()); + if (ringCache_ == nullptr) { + AUDIO_ERR_LOG("ringCache create fail"); + } +} + +HpaeSinkVirtualOutputNode::~HpaeSinkVirtualOutputNode() +{ +#ifdef ENABLE_HIDUMP_DFX + AUDIO_INFO_LOG("NodeId: %{public}u NodeName: %{public}s destructed.", + GetNodeId(), GetNodeName().c_str()); +#endif +} + +void HpaeSinkVirtualOutputNode::DoRenderProcess() +{ + Trace trace("HpaeSinkVirtualOutputNode::DoRenderProcess " + GetTraceInfo()); + std::vector &outputVec = inputStream_.ReadPreOutputData(); + CHECK_AND_RETURN(!outputVec.empty()); + HpaePcmBuffer *outputData = outputVec.front(); + + OptResult result = ringCache_->Enqueue( + {reinterpret_cast(outputData->GetPcmDataBuffer()), outputData->DataSize()}); + CHECK_AND_RETURN_LOG(retsult.ret == OPERATION_SUCCESS, "ringCache enqueue fail"); +} + +void HpaeSinkVirtualOutputNode::DoProcess() +{ + Trace trace("HpaeSinkVirtualOutputNode::DoProcess " + GetTraceInfo()); + OptResult result = ringCache_->Dequeue( + {reinterpret_cast(outputAudioBuffer_.GetPcmDataBuffer()), outputAudioBuffer_.DataSize()}); + CHECK_AND_RETURN_LOG(retsult.ret == OPERATION_SUCCESS, "ringCache dequeue fail"); + outputStream_.WriteDataToOutput(&outputAudioBuffer_); + if (auto callback = GetNodeStatusCallback().lock()) { + callback->OnNotifyQueue(); + } +} + +int32_t HpaeSinkVirtualOutputNode::PeekAudioData(uint8_t **buffer, const size_t &bufferSize) +{ + Trace trace("HpaeSinkVirtualOutputNode::PeekAudioData" + GetTraceInfo()); + std::lock_guard lock(mutex_); + DoProcess(); + ConvertFromFloat(GetBitWidth(), GetChannelCount() * GetFrameLen(), outputAudioBuffer_.GetPcmDataBuffer(), + renderFrameData_.data()); + CHECK_AND_RETURN_RET_LOG(bufferSize == outputAudioBuffer_.DataSize(), ERROR_INVALID_PARAM, "buffersize error"); + *buffer = reinterpret_cast(renderFrameData_.data()); + return SUCCESS; +} + +bool HpaeSinkVirtualOutputNode::Reset() +{ + const auto preOutputMap = inputStream_.GetPreOutputMap(); + for (const auto &preOutput : preOutputMap) { + OutputPort *output = preOutput.first; + inputStream_.DisConnect(output); + } + return true; +} + +bool HpaeSinkVirtualOutputNode::ResetAll() +{ + const auto preOutputMap = inputStream_.GetPreOutputMap(); + for (const auto &preOutput : preOutputMap) { + OutputPort *output = preOutput.first; + std::shared_ptr hpaeNode = preOutput.second; + if (hpaeNode->ResetAll()) { + inputStream_.DisConnect(output); + } + } + return true; +} + +void HpaeSinkVirtualOutputNode::Connect(const std::shared_ptr> &preNode) override +{ + inputStream_.Connect(preNode->GetSharedInstance(), preNode->GetOutputPort()); +#ifdef ENABLE_HIDUMP_DFX + if (auto callback = GetNodeStatusCallback().lock()) { + callback->OnNotifyDfxNodeInfo(true, GetNodeId(), preNode->GetSharedInstance()->GetNodeInfo()); + } +#endif +} + +void HpaeSinkVirtualOutputNode::DisConnect(const std::shared_ptr> &preNode) override +{ + inputStream_.DisConnect(preNode->GetOutputPort()); +#ifdef ENABLE_HIDUMP_DFX + if (auto callback = GetNodeStatusCallback().lock()) { + auto preNodeReal = preNode->GetSharedInstance(); + callback->OnNotifyDfxNodeInfo(false, preNodeReal->GetNodeId(), preNodeReal->GetNodeInfo()); + } +#endif +} + +int32_t HpaeSinkVirtualOutputNode::RenderSinkInit() +{ + CHECK_AND_RETURN_RET_LOG(ringCache_ != nullptr, ERR_INVALID_OPERATION, "init fail, ringcache is null"); + SetSinkState(STREAM_MANAGER_IDLE); + return SUCCESS; +} + +int32_t HpaeSinkVirtualOutputNode::RenderSinkDeInit() +{ + SetSinkState(STREAM_MANAGER_RELEASED); + return SUCCESS; +} + +int32_t HpaeSinkVirtualOutputNode::RenderSinkStart(void) +{ + SetSinkState(STREAM_MANAGER_RUNNING); + return SUCCESS; +} + +int32_t HpaeSinkVirtualOutputNode::RenderSinkStop(void) +{ + if (ringCache_ != nullptr) { + ringCache_.ResetBuffer(); + } + SetSinkState(STREAM_MANAGER_SUSPENDED); + return SUCCESS; +} + +size_t HpaeSinkVirtualOutputNode::GetPreOutNum() +{ + return inputStream_.GetPreOutputNum(); +} + +StreamManagerState HpaeSinkVirtualOutputNode::GetSinkState(void) +{ + return state_; +} + +int32_t HpaeSinkVirtualOutputNode::SetSinkState(StreamManagerState sinkState) +{ + AUDIO_INFO_LOG("Sink[%{public}s] state change:[%{public}s]-->[%{public}s]", + GetDeviceClass().c_str(), ConvertStreamManagerState2Str(state_).c_str(), + ConvertStreamManagerState2Str(sinkState).c_str()); + state_ = sinkState; + return SUCCESS; +} + +uint32_t HpaeSinkVirtualOutputNode::GetLatency() +{ + return 0; +} + +bool HpaeSinkVirtualOutputNode::GetIsReadFinished() +{ + OptResult result = ringCache_->GetWritableSize(); + CHECK_AND_RETURN_RET_LOG(result.ret == OPERATION_SUCCESS, false, + "ringCache get writable invalid size : %{public}zu", result.size); + return result.size != 0; +} + +int32_t HpaeSinkVirtualOutputNode::ReloadNode(hpaeNodeInfo nodeInfo) +{ + std::lock_guard lock(mutex_); + nodeInfo.nodeId = GetNodeId(); // not change nodeId + SetNodeInfo(nodeInfo); + pcmBufferInfo_ = PcmBufferInfo(nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate); + outputAudioBuffer_.ReConfig(pcmBufferInfo_); + size_t size = GetRingCacheSize(); + if (ringCache_ == nullptr) { + ringCache_ = AudioRingCache::Create(size); + } else { + ringCache_->ReConfig(size, false); + } + return SUCCESS; +} + +size_t HpaeSinkVirtualOutputNode::GetRingCacheSize() +{ + size_t frameBytes = GetChannelCount() * static_cast(GetSizeFromFormat(GetBitWidth())) * + GetSampleRate() * DEFAULT_FRAME_LEN_MS / MS_PER_SECOND; + return DEFAULT_RING_BUFFER_NUM * frameBytes; +} +} // namespace HPAE +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/audio_engine/node/src/hpae_source_process_cluster.cpp b/services/audio_engine/node/src/hpae_source_process_cluster.cpp index 25e27def89..986fe2a151 100644 --- a/services/audio_engine/node/src/hpae_source_process_cluster.cpp +++ b/services/audio_engine/node/src/hpae_source_process_cluster.cpp @@ -25,8 +25,9 @@ namespace OHOS { namespace AudioStandard { namespace HPAE { -HpaeSourceProcessCluster::HpaeSourceProcessCluster(HpaeNodeInfo& nodeInfo) - : HpaeNode(nodeInfo), captureEffectNode_(std::make_shared(nodeInfo)) +HpaeSourceProcessCluster::HpaeSourceProcessCluster(HpaeNodeInfo& nodeInfo) // nodeInfo maybe sourceinputnode info + : HpaeNode(nodeInfo), captureEffectNode_(std::make_shared(nodeInfo)), + mixerNode_(std::make_shared(nodeInfo)) { #ifdef ENABLE_HIDUMP_DFX SetNodeName("HpaeSourceProcessCluster"); @@ -49,46 +50,60 @@ void HpaeSourceProcessCluster::DoProcess() bool HpaeSourceProcessCluster::Reset() { - captureEffectNode_->Reset(); + if (captureEffectNode != nullptr) { + captureEffectNode_->Reset(); + } + mixerNode_->Reset(); for (auto fmtConverterNode : fmtConverterNodeMap_) { fmtConverterNode.second->Reset(); } + for (auto fmtConverterNode : injectorFmtConverterNodeMap_) { + fmtConverterNode.second->Reset(); + } return true; } bool HpaeSourceProcessCluster::ResetAll() { - return captureEffectNode_->ResetAll(); + return captureEffectNode_ != nullptr ? captureEffectNode_->ResetAll() : mixerNode_->ResetAll(); } std::shared_ptr HpaeSourceProcessCluster::GetSharedInstance() { + if (captureEffectNode_ == nullptr) { + return mixerNode_; + } return captureEffectNode_; } OutputPort *HpaeSourceProcessCluster::GetOutputPort() { - return captureEffectNode_->GetOutputPort(); + return captureEffectNode_ != nullptr ? captureEffectNode_->GetOutputPort() : mixerNode_->GetOutputPort(); } std::shared_ptr HpaeSourceProcessCluster::GetSharedInstance(HpaeNodeInfo &nodeInfo) { std::string sourceOutputNodeKey = TransNodeInfoToStringKey(nodeInfo); - HpaeNodeInfo effectNodeInfo; - captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); + HpaeNodeInfo effectNodeInfo = mixerNode_->GetNodeInfo(); + if (captureEffectNode_ != nullptr) { + captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); + } std::string effectNodeKey = TransNodeInfoToStringKey(effectNodeInfo); AUDIO_INFO_LOG("sourceOutput:[%{public}s] effectNode:[%{public}s]", sourceOutputNodeKey.c_str(), effectNodeKey.c_str()); if (CheckHpaeNodeInfoIsSame(nodeInfo, effectNodeInfo)) { AUDIO_INFO_LOG("Specification of sourceOutputNode is same with capture effect"); - return captureEffectNode_; + if (captureEffectNode_ != nullptr) { + return captureEffectNode_; + } + return mixerNode; } if (!SafeGetMap(fmtConverterNodeMap_, sourceOutputNodeKey)) { fmtConverterNodeMap_[sourceOutputNodeKey] = std::make_shared(effectNodeInfo, nodeInfo); fmtConverterNodeMap_[sourceOutputNodeKey]->SetSourceNode(true); } - fmtConverterNodeMap_[sourceOutputNodeKey]->Connect(captureEffectNode_); + fmtConverterNodeMap_[sourceOutputNodeKey]->Connect(mixerNode_); return fmtConverterNodeMap_[sourceOutputNodeKey]; } @@ -102,7 +117,7 @@ OutputPort *HpaeSourceProcessCluster::GetOutputPort(HpaeNodeInf sourceOutputNodeKey.c_str(), effectNodeKey.c_str()); if (CheckHpaeNodeInfoIsSame(nodeInfo, effectNodeInfo)) { AUDIO_INFO_LOG("Specification of sourceOutputNode is same with capture effect"); - return captureEffectNode_->GetOutputPort(); + return captureEffectNode_ != nullptr ? captureEffectNode_->GetOutputPort() : mixerNode_->GetOutputPort(); } CHECK_AND_RETURN_RET_LOG(SafeGetMap(fmtConverterNodeMap_, sourceOutputNodeKey), captureEffectNode_->GetOutputPort(), @@ -111,7 +126,7 @@ OutputPort *HpaeSourceProcessCluster::GetOutputPort(HpaeNodeInf // disconnect fmtConverterNode->upEffectNode AUDIO_INFO_LOG("disconnect fmtConverterNode between effectnode[[%{public}s] and sourceoutputnode[%{public}s]", effectNodeKey.c_str(), sourceOutputNodeKey.c_str()); - fmtConverterNodeMap_[sourceOutputNodeKey]->DisConnect(captureEffectNode_); + fmtConverterNodeMap_[sourceOutputNodeKey]->DisConnect(mixerNode_); } return fmtConverterNodeMap_[sourceOutputNodeKey]->GetOutputPort(); } @@ -133,37 +148,97 @@ void HpaeSourceProcessCluster::DisConnect(const std::shared_ptr>& preNode, HpaeNodeInfo &nodeInfo) { - captureEffectNode_->ConnectWithInfo(preNode, nodeInfo); + if (captureEffectNode_) { + captureEffectNode_->ConnectWithInfo(preNode, nodeInfo); + } else { + mixerNode_->ConnectWithInfo(preNode, nodeInfo); + } } void HpaeSourceProcessCluster::DisConnectWithInfo(const std::shared_ptr>& preNode, HpaeNodeInfo &nodeInfo) { - captureEffectNode_->DisConnectWithInfo(preNode, nodeInfo); + if (captureEffectNode_) { + captureEffectNode_->DisConnectWithInfo(preNode, nodeInfo); + } else { + mixerNode_->DisConnectWithInfo(preNode, nodeInfo); + } +} + +void HpaeSourceProcessCluster::ConnectInjector(const std::shared_ptr>& preNode) +{ + AUDIO_INFO_LOG("connect injector sinkOutputNode in processcluster"); + CHECK_AND_RETURN_(preNode != nullptr, "pre sinkOutputNode is nullptr"); + HpaeNodeInfo sinkNodeInfo = preNode->GetNodeInfo(); + HpaeNodeInfo mixerNodeInfo = mixerNode_->GetNodeInfo(); + if (CheckHpaeNodeInfoIsSame(sinkNodeInfo, mixerNodeInfo)) { + AUDIO_INFO_LOG("Specification of sinkOutputNode is same with mixerNode"); + mixerNode_->Connect(preNode); + } else { + injectorFmtConverterNodeMap_[preNode] = + std::make_shared(HpaeAudioFormatConverterNode)(sinkNodeInfo, mixerNodeInfo); + mixerNode_->Connect(injectorFmtConverterNodeMap_[preNode]); + injectorFmtConverterNodeMap_[preNode]->Connect(preNode); + } +} + +void HpaeSourceProcessCluster::DisConnectInjector(const std::shared_ptr>& preNode) +{ + AUDIO_INFO_LOG("disconnect injector sinkOutputNode in processcluster"); + CHECK_AND_RETURN_(preNode != nullptr, "pre sinkOutputNode is nullptr"); + HpaeNodeInfo sinkNodeInfo = preNode->GetNodeInfo(); + HpaeNodeInfo mixerNodeInfo = mixerNode_->GetNodeInfo(); + if (CheckHpaeNodeInfoIsSame(sinkNodeInfo, mixerNodeInfo)) { + AUDIO_INFO_LOG("Specification of sinkOutputNode is same with mixerNode"); + mixerNode_->DisConnect(preNode); + } else { + injectorFmtConverterNodeMap_[preNode]->Connect(preNode); + mixerNode_->DisConnect(injectorFmtConverterNodeMap_[preNode]); + injectorFmtConverterNodeMap_.erase(preNode); + } } bool HpaeSourceProcessCluster::GetCapturerEffectConfig(HpaeNodeInfo &nodeInfo, HpaeSourceBufferType type) { - return captureEffectNode_->GetCapturerEffectConfig(nodeInfo, type); + if (captureEffectNode_ != nullptr) { + return captureEffectNode_->GetCapturerEffectConfig(nodeInfo, type); + } + nodeInfo = mixerNode_->GetNodeInfo(); + return true; } size_t HpaeSourceProcessCluster::GetOutputPortNum() { + CHECK_AND_RETURN_RET(captureEffectNode_ != nullptr, mixerNode_->GetOutputPortNum()); return captureEffectNode_->GetOutputPortNum(); } int32_t HpaeSourceProcessCluster::CaptureEffectCreate(uint64_t sceneKeyCode, CaptureEffectAttr attr) { CHECK_AND_RETURN_RET_LOG(captureEffectNode_, ERROR_ILLEGAL_STATE, "captureEffectNode_ is nullptr"); - return captureEffectNode_->CaptureEffectCreate(sceneKeyCode, attr); + HpaeNodeInfo nodeInfo; + if (captureEffectNode_->CaptureEffectCreate(sceneKeyCode, attr) != 0 || GetCapturerEffectConfig(nodeInfo)) { + captureEffectNode_ = nullptr; + return ERROR_ILLEGAL_STATE; + } + // create captureEffectNode, updata mixerNode info by effectnode info + mixerNode_ = std::make_shared(nodeInfo); + mixerNode_->Connect(captureEffectNode_); + return 0; } int32_t HpaeSourceProcessCluster::CaptureEffectRelease(uint64_t sceneKeyCode) { CHECK_AND_RETURN_RET_LOG(captureEffectNode_, ERROR_ILLEGAL_STATE, "captureEffectNode_ is nullptr"); + mixerNode_->DisConnect(captureEffectNode_); return captureEffectNode_->CaptureEffectRelease(sceneKeyCode); } +bool HpaeSourceProcessCluster::IsEffectNodeValid() +{ + return captureEffectNode_ != nullptr; +} + // for ut test uint32_t HpaeSourceProcessCluster::GetCapturerEffectNodeUseCount() { diff --git a/services/audio_engine/test/unittest/manager/hpae_manager_test.cpp b/services/audio_engine/test/unittest/manager/hpae_manager_test.cpp index c757359e01..851ed22dff 100644 --- a/services/audio_engine/test/unittest/manager/hpae_manager_test.cpp +++ b/services/audio_engine/test/unittest/manager/hpae_manager_test.cpp @@ -41,6 +41,8 @@ constexpr int32_t TEST_STREAM_UID = 111111; constexpr int32_t TEST_SLEEP_TIME_20 = 20; constexpr int32_t TEST_SLEEP_TIME_40 = 40; constexpr int32_t SESSION_ID_NOEXIST = 100000; +constexpr uint32_t DEFAULT_FRAME_LEN_MS = 20; +constexpr uint32_t MS_PER_SECOND = 1000; class HpaeManagerUnitTest : public testing::Test { public: @@ -1796,4 +1798,101 @@ HWTEST_F(HpaeManagerUnitTest, CloseInCoreAudioPort_005, TestSize.Level1) hpaeManager_->coreSource_ = "mic"; EXPECT_EQ(hpaeManager_->CloseInAudioPort(sourceName), SUCCESS); } + +HWTEST_F(HpaeManagerUnitTest, InjectorToPrimaryCapturer, TestSize.Level1) +{ + EXPECT_NE(hpaeManager_, nullptr); + hpaeManager_->Init(); + sleep(1); + EXPECT_EQ(hpaeManager_->IsInit(), true); + std::shared_ptr callback = std::make_shared(); + hpaeManager_->RegisterSerivceCallback(callback); + + AudioModuleInfo moduleInfo = GetSinkAudioModeInfo("virtual"); // todo : rewrite correct name + EXPECT_EQ(hpaeManager_->OpenAudioPort(moduleInfo), SUCCESS); + WaitForMsgProcessing(hpaeManager_); + int32_t injectorPortId = callback->GetPortId(); + + auto it = hpaeManager_->sinkVirtualOutputNodeMap_.find(injectorPortId); + EXPECT_EQ(it != hpaeManager_->sinkVirtualOutputNodeMap_.end(), true); + auto sinkOutputNode = it->second; + EXPECT_EQ(sinkOutputNode != nullptr, true); + HpaeNodeInfo nodeInfo = sinkOutputNode->GetNodeInfo(); + EXPECT_EQ(moduleInfo.channels, std::to_string(nodeInfo.channels)); + EXPECT_EQ(moduleInfo.rate, std::to_string(nodeInfo.samplingRate)); + + AudioModuleInfo moduleInfo2 = GetSourceAudioModeInfo(); + EXPECT_EQ(hpaeManager_->OpenAudioPort(moduleInfo2), SUCCESS); + WaitForMsgProcessing(hpaeManager_); + int32_t capturerPortId = callback->GetPortId(); + + HpaeStreamInfo streamInfo = GetRenderStreamInfo(); + streamInfo.deviceName = moduleInfo.name; + hpaeManager_->CreateStream(streamInfo); + WaitForMsgProcessing(hpaeManager_); + + HpaeStreamInfo streamInfo2 = GetCaptureStreamInfo(); + streamInfo2.deviceName = moduleInfo2.name; + streamInfo.sourceType = SOURCE_TYPE_MIC; + hpaeManager_->CreateStream(streamInfo2); + WaitForMsgProcessing(hpaeManager_); + + hpaeManager_->AddCaptureInjector(injectorPortId, capturerPortId, streamInfo2.sourceType); + hpaeManager_->Start(HPAE_STREAM_CLASS_TYPE_RECORD, streamInfo2.sessionId); + hpaeManager_->Start(HPAE_STREAM_CLASS_TYPE_PLAY, streamInfo.sessionId); + sleep(3); // 3s for sleep + hpaeManager_->Stop(HPAE_STREAM_CLASS_TYPE_RECORD, streamInfo2.sessionId); + hpaeManager_->Stop(HPAE_STREAM_CLASS_TYPE_PLAY, streamInfo.sessionId); + WaitForMsgProcessing(hpaeManager_); + hpaeManager_->RemoveCaptureInjector(injectorPortId, capturerPortId, streamInfo2.sourceType); + WaitForMsgProcessing(hpaeManager_); + hpaeManager_->CloseAudioPort(injectorPortId); + hpaeManager_->CloseAudioPort(capturerPortId); + WaitForMsgProcessing(hpaeManager_); +} + +HWTEST_F(HpaeManagerUnitTest, InjectorToEndPointCapturer, TestSize.Level1) +{ + EXPECT_NE(hpaeManager_, nullptr); + hpaeManager_->Init(); + sleep(1); + EXPECT_EQ(hpaeManager_->IsInit(), true); + std::shared_ptr callback = std::make_shared(); + hpaeManager_->RegisterSerivceCallback(callback); + + AudioModuleInfo moduleInfo = GetSinkAudioModeInfo("virtual"); // todo : rewrite correct name + EXPECT_EQ(hpaeManager_->OpenAudioPort(moduleInfo), SUCCESS); + WaitForMsgProcessing(hpaeManager_); + int32_t injectorPortId = callback->GetPortId(); + + auto it = hpaeManager_->sinkVirtualOutputNodeMap_.find(injectorPortId); + EXPECT_EQ(it != hpaeManager_->sinkVirtualOutputNodeMap_.end(), true); + auto sinkOutputNode = it->second; + EXPECT_EQ(sinkOutputNode != nullptr, true); + HpaeNodeInfo nodeInfo = sinkOutputNode->GetNodeInfo(); + EXPECT_EQ(moduleInfo.channels, std::to_string(nodeInfo.channels)); + EXPECT_EQ(moduleInfo.rate, std::to_string(nodeInfo.samplingRate)); + + HpaeStreamInfo streamInfo = GetRenderStreamInfo(); + streamInfo.deviceName = moduleInfo.name; + hpaeManager_->CreateStream(streamInfo); + WaitForMsgProcessing(hpaeManager_); + + hpaeManager_->Start(HPAE_STREAM_CLASS_TYPE_PLAY, streamInfo.sessionId); + WaitForMsgProcessing(hpaeManager_); + + uint8_t *buffer = nullptr; + size_t bufferSize = nodeInfo.samplingRate * nodeInfo.channels * DEFAULT_FRAME_LEN_MS * + static_cast(GetSizeFromFormat(nodeInfo.format)) / MS_PER_SECOND; + AudioStreamInfo retStreamInfo; + for (size_t i = 0; i < 10; i++) { // 10 for loop times + EXPECT_EQ(hpaeManager_->PeekAudioData(injectorPortId, &buffer, bufferSize, retStreamInfo), SUCCESS); + EXPECT_EQ(buffer != nullptr, true); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 50ms for sleep + } + hpaeManager_->Stop(HPAE_STREAM_CLASS_TYPE_PLAY, streamInfo.sessionId); + WaitForMsgProcessing(hpaeManager_); + hpaeManager_->CloseAudioPort(injectorPortId); + WaitForMsgProcessing(hpaeManager_); +} } // namespace \ No newline at end of file diff --git a/test/fuzztest/hpaecapturermanager_fuzzer/BUILD.gn b/test/fuzztest/hpaecapturermanager_fuzzer/BUILD.gn index 11a5de8bfa..cff0069737 100644 --- a/test/fuzztest/hpaecapturermanager_fuzzer/BUILD.gn +++ b/test/fuzztest/hpaecapturermanager_fuzzer/BUILD.gn @@ -24,6 +24,7 @@ ohos_fuzztest("HpaeCapturerManagerFuzzTest") { "../../../frameworks/native/audioschedule/include", "../../../frameworks/native/hdiadapter_new/include/manager", "../../../interfaces/inner_api/native/audiocommon/include", + "../../../services/audio_service/common/include/limiter", "../../../services/audio_service/server/include", "../../../services/audio_engine/buffer", "../../../services/audio_engine/manager/include", -- Gitee From 0ad41792a61f2ebfb88119df1d9b54a6f1ea8a06 Mon Sep 17 00:00:00 2001 From: ch4r13s Date: Sat, 13 Sep 2025 17:58:02 +0800 Subject: [PATCH 2/5] proaudio injector Signed-off-by: ch4r13s --- .../include/hpae_injector_renderer_manager.h | 14 + .../src/hpae_injector_renderer_manager.cpp | 664 ++++++++++++++++++ .../include/hpae_virtual_process_cluster.h | 52 ++ .../node/src/hpae_virtual_process_cluster.cpp | 139 ++++ 4 files changed, 869 insertions(+) create mode 100644 services/audio_engine/manager/include/hpae_injector_renderer_manager.h create mode 100644 services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp create mode 100644 services/audio_engine/node/include/hpae_virtual_process_cluster.h create mode 100644 services/audio_engine/node/src/hpae_virtual_process_cluster.cpp diff --git a/services/audio_engine/manager/include/hpae_injector_renderer_manager.h b/services/audio_engine/manager/include/hpae_injector_renderer_manager.h new file mode 100644 index 0000000000..5dd09178ce --- /dev/null +++ b/services/audio_engine/manager/include/hpae_injector_renderer_manager.h @@ -0,0 +1,14 @@ +/* + * 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. + */ diff --git a/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp b/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp new file mode 100644 index 0000000000..4551d1f9ee --- /dev/null +++ b/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp @@ -0,0 +1,664 @@ +/* + * 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. + */ + +HpaeInjectorRendererManager::HpaeInjectorRendererManager(HpaeSinkInfo &sinkInfo) + : hpaeNoLockQueue_(CURRENT_REQUEST_COUNT), sinkInfo_(sinkInfo) +{} + +HpaeInjectorRendererManager::~HpaeInjectorRendererManager() +{ + AUDIO_INFO_LOG("destructor offload renderer"); + if (isInit_.load()) { + DeInit(); + } +} + +int32_t HpaeInjectorRendererManager::CreateStream(const HpaeStreamInfo &streamInfo) +{ + if (!IsInit()) { + return ERR_INVALID_OPERATION; + } + auto request = [this, streamInfo]() { + Trace trace("HpaeInjectorRendererManager::CreateStream id[" + std::to_string(streamInfo.sessionId) + "]"); + AUDIO_INFO_LOG("CreateStream sessionId %{public}u deviceName %{public}s", streamInfo.sessionId, + sinkInfo_.deviceName.c_str()); + CreateInputSession(streamInfo); + SetSessionState(streamInfo.sessionId, HPAE_SESSION_PREPARED); + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::DestroyStream(uint32_t sessionId) +{ + if (!IsInit()) { + return ERR_INVALID_OPERATION; + } + auto request = [this, sessionId]() { + Trace trace("HpaeInjectorRendererManager::DestroyStream id[" + std::to_string(sessionId) + "]"); + AUDIO_INFO_LOG("DestroyStream sessionId %{public}u", sessionId); + CHECK_AND_RETURN_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), + "DestroyStream not find sessionId %{public}u", sessionId); + SetSessionState(sessionId, HPAE_SESSION_RELEASED); + DeleteInputSession(sessionId); + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::Start(uint32_t sessionId) +{ + auto request = [this, sessionId]() { + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::Start"); + CHECK_AND_RETURN_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), "sessionId %{public}u not found", sessionId); + ConnectInputSession(sessionId); + SetSessionState(sessionId, HPAE_SESSION_RUNNING); + SetSessionFade(sessionId, OPERATION_STARTED); + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::Pause(uint32_t sessionId) +{ + auto request = [this, sessionId]() { + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::Pause"); + CHECK_AND_RETURN_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), "sessionId %{public}u not found", sessionId); + if (!SetSessionFade(sessionId, OPERATION_PAUSED)) { + DisConnectInputSession(sessionId); + } + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::Flush(uint32_t sessionId) +{ + auto request = [this, sessionId]() { + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::Flush"); + AUDIO_INFO_LOG("Flush sessionId %{public}u deviceName %{public}s", sessionId, sinkInfo_.deviceName.c_str()); + CHECK_AND_RETURN_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), + "Flush not find sessionId %{public}u", sessionId); + sinkInputNodeMap_[sessionId]->Flush(); + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::Drain(uint32_t sessionId) +{ + auto request = [this, sessionId]() { + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::Drain"); + AUDIO_INFO_LOG("Drain sessionId %{public}u deviceName %{public}s ", sessionId, sinkInfo_.deviceName.c_str()); + CHECK_AND_RETURN_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), + "Drain not find sessionId %{public}u", sessionId); + sinkInputNodeMap_[sessionId]->Drain(); + if (sessionNodeMap_[sessionId].state != HPAE_SESSION_RUNNING) { + AUDIO_INFO_LOG("TriggerCallback Drain sessionId %{public}u", sessionId); + TriggerCallback(UPDATE_STATUS, + HPAE_STREAM_CLASS_TYPE_PLAY, + sessionId, + sessionNodeMap_[sessionId].state, + OPERATION_DRAINED); + } + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::Stop(uint32_t sessionId) +{ + auto request = [this, sessionId]() { + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::Stop"); + CHECK_AND_RETURN_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), "Stop not find sessionId %{public}u", sessionId); + if (!SetSessionFade(sessionId, OPERATION_STOPPED)) { + DisConnectInputSession(sessionId); + } + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::Release(uint32_t sessionId) +{ + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::Release"); + CHECK_AND_RETURN_RET_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), ERROR, + "Release not find sessionId %{public}u", sessionId); + return DestroyStream(sessionId); +} + +int32_t HpaeInjectorRendererManager::MoveStream(uint32_t sessionId, const std::string& sinkName) +{ + if (!IsInit()) { + MoveStreamSync(sessionId, sinkName); + } else { + auto request = [this, sessionId, sinkName]() { MoveStreamSync(sessionId, sinkName); }; + SendRequest(request, __func__); + } + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::MoveAllStream(const std::string& sinkName, const std::vector& sessionIds, + MoveSessionType moveType) +{ + if (!IsInit()) { + AUDIO_INFO_LOG("sink is not init ,use sync mode move to:%{public}s.", sinkName.c_str()); + MoveAllStreamToNewSink(sinkName, sessionIds, moveType); + } else { + AUDIO_INFO_LOG("sink is init ,use async mode move to:%{public}s.", sinkName.c_str()); + auto request = [this, sinkName, sessionIds, moveType]() { + MoveAllStreamToNewSink(sinkName, sessionIds, moveType); + }; + SendRequest(request, __func__); + } + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::SuspendStreamManager(bool isSuspend) +{ + auto request = [this, isSuspend]() { + if (isSuspend_ == isSuspend) { + return; + } + AUDIO_INFO_LOG("suspend audio device: %{public}s, isSuspend: %{public}d", + sinkInfo_.deviceName.c_str(), isSuspend); + isSuspend_ = isSuspend; + if (isSuspend_) { + if (sinkOutputNode_ != nullptr) { + sinkOutputNode_->RenderSinkStop(); + } + } else if (sinkOutputNode_ != nullptr && sinkOutputNode_->GetState() != STREAM_MANAGER_RUNNING && + CheckIsStreamRunning()) { + sinkOutputNode_->RenderSinkStart(); + } + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::SetMute(bool isMute) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +void HpaeInjectorRendererManager::Process() +{ + Trace trace("HpaeInjectorRendererManager::Process"); + if (sinkOutputNode_ != nullptr && IsRunning()) { + sinkOutputNode_->DoRenderProcess(); + } +} + +void HpaeInjectorRendererManager::HandleMsg() +{ + hpaeNoLockQueue_.HandleRequests(); +} + +int32_t HpaeInjectorRendererManager::Init(bool isReload) +{ + // after set sinkoutputnode + hpaeSignalProcessThread_ = std::make_unique(); + auto request = [this, isReload] { + InitManager(isReload); + }; + SendRequest(request, __func__, true); + hpaeSignalProcessThread_->ActivateThread(shared_from_this()); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::DeInit(bool isMoveDefault) +{ + DeinitInner(isMoveDefault); + return SUCCESS; +} + +void HpaeInjectorRendererManager::DeinitInner(bool isMoveDefault, bool fromReload) +{ + if (hpaeSignalProcessThread_ != nullptr) { + hpaeSignalProcessThread_->DeactivateThread(); + hpaeSignalProcessThread_ = nullptr; + } + hpaeNoLockQueue_.HandleRequests(); + if (isMoveDefault) { + std::string sinkName = ""; + std::vector ids; + AUDIO_INFO_LOG("move all sink to default sink"); + MoveAllStreamToNewSink(sinkName, ids, MOVE_ALL); + } + if (sinkOutputNode_ != nullptr) { + sinkOutputNode_->RenderSinkStop(); + sinkOutputNode_->RenderSinkDeInit(); + sinkOutputNode_->ResetAll(); + if (!fromReload) { + sinkOutputNode_ = nullptr; // reload not delete sinkoutputnode + } + } + isInit_.store(false); +} + +bool HpaeInjectorRendererManager::IsInit() +{ + return isInit_.load(); +} + +bool HpaeInjectorRendererManager::IsRunning(void) +{ + if (sinkOutputNode_ != nullptr && hpaeSignalProcessThread_ != nullptr) { + return sinkOutputNode_->GetState() == STREAM_MANAGER_RUNNING && sinkOutputNode_->GetIsReadFinished() && + hpaeSignalProcessThread_->IsRunning(); + } + return false; +} + +bool HpaeInjectorRendererManager::IsMsgProcessing() +{ + return !hpaeNoLockQueue_.IsFinishProcess(); +} + +bool HpaeInjectorRendererManager::DeactivateThread() +{ + if (hpaeSignalProcessThread_ != nullptr) { + hpaeSignalProcessThread_->DeactivateThread(); + hpaeSignalProcessThread_ = nullptr; + } + hpaeNoLockQueue_.HandleRequests(); + return true; +} + +int32_t HpaeInjectorRendererManager::SetClientVolume(uint32_t sessionId, float volume) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::SetRate(uint32_t sessionId, int32_t rate) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::SetAudioEffectMode(uint32_t sessionId, int32_t effectMode) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::GetAudioEffectMode(uint32_t sessionId, int32_t &effectMode) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::SetPrivacyType(uint32_t sessionId, int32_t privacyType) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::GetPrivacyType(uint32_t sessionId, int32_t &privacyType) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::RegisterWriteCallback( + uint32_t sessionId, const std::weak_ptr &callback) +{ + auto request = [this, sessionId, callback]() { + CHECK_AND_RETURN_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), + "RegisterWriteCallback not find sessionId %{public}u", sessionId); + sinkInputNodeMap_[sessionId]->RegisterWriteCallback(callback); + }; + SendRequest(request, __func__); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::RegisterReadCallback( + uint32_t sessionId, const std::weak_ptr &callback) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +size_t HpaeInjectorRendererManager::GetWritableSize(uint32_t sessionId) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return 0; +} + +int32_t HpaeInjectorRendererManager::UpdateSpatializationState(uint32_t sessionId, bool spatializationEnabled, + bool headTrackingEnabled) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::UpdateMaxLength(uint32_t sessionId, uint32_t maxLength) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +std::vector HpaeInjectorRendererManager::GetAllSinkInputsInfo() +{ + return {}; +} + +int32_t HpaeInjectorRendererManager::GetSinkInputInfo(uint32_t sessionId, HpaeSinkInputInfo &sinkInputInfo) +{ + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::RefreshProcessClusterByDevice() +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +HpaeSinkInfo HpaeInjectorRendererManager::GetSinkInfo() +{ + return HpaeSinkInfo{}; +} + +int32_t HpaeInjectorRendererManager::AddNodeToSink(const std::shared_ptr &node) +{ + auto request = [this, node]() { + AddSingleNodeToSink(node); + }; + SendRequest(request, __func__); + return SUCCESS; +} + +void HpaeInjectorRendererManager::AddSingleNodeToSink(const std::shared_ptr &node, bool isConnect) +{ + Trace trace("HpaeInjectorRendererManager::AddSingleNodeToSink"); + HpaeNodeInfo nodeInfo = node->GetNodeInfo(); + nodeInfo.deviceClass = sinkInfo_.deviceClass; + nodeInfo.deviceNetId = sinkInfo_.deviceNetId; + nodeInfo.historyFrameCount = 0; + nodeInfo.statusCallback = weak_from_this(); + node->SetNodeInfo(nodeInfo); + uint32_t sessionId = nodeInfo.sessionId; + + sinkInputNodeMap_[sessionId] = node; + SetSessionState(sessionId, node->GetState()); + if (node->GetState() == HPAE_SESSION_RUNNING) { + ConnectInputSession(sessionId); + } + AUDIO_INFO_LOG("[FinishMove] session:%{public}u to sink:offload", sessionId); +} + +int32_t HpaeInjectorRendererManager::AddAllNodesToSink( + const std::vector> &sinkInputs, bool isConnect) +{ + auto request = [this, sinkInputs, isConnect]() { + for (const auto &it : sinkInputs) { + AddSingleNodeToSink(it, isConnect); + } + }; + return SUCCESS; +} + +void HpaeInjectorRendererManager::OnNodeStatusUpdate(uint32_t sessionId, IOperation operation) +{ + // from sinkinputnode, maybe underflow, but underflow maybe not arise in this situation + TriggerCallback(UPDATE_STATUS, HPAE_STREAM_CLASS_TYPE_PLAY, sessionId, + sessionNodeMap_[sessionId].state, operation); +} + +void HpaeInjectorRendererManager::OnFadeDone(uint32_t sessionId, IOperation operation) +{ + auto request = [this, sessionId, operation]() { + AUDIO_INFO_LOG("Fade done, call back at RendererManager, callback at injectorRendererManager"); + DisConnectInputSession(sessionId); + HpaeSessionState state = operation == OPERATION_STOPPED ? HPAE_SESSION_STOPPED : HPAE_SESSION_PAUSED; + if (SafeGetMap(sinkInputNodeMap_, sessionId)) { + SetSessionState(sessionId, state); + } + TriggerCallback(UPDATE_STATUS, HPAE_STREAM_CLASS_TYPE_PLAY, sessionId, state, operation); + }; + SendRequest(request, __func__); +} + +void HpaeInjectorRendererManager::OnNotifyQueue() +{ + CHECK_AND_RETURN_LOG(hpaeSignalProcessThread_, "HpaeInjectorRendererManager hpaeSignalProcessThread_ is nullptr"); + // Trace trace("HpaeInjectorRendererManager::OnNotifyQueue()"); + hpaeSignalProcessThread_->Notify(); +} + +std::string HpaeInjectorRendererManager::GetThreadName() +{ + return sinkInfo_.deviceName; +} + +int32_t HpaeInjectorRendererManager::DumpSinkInfo() +{ + // todo : hidumper info + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::ReloadRenderManager(const HpaeSinkInfo &sinkInfo, bool isReload) +{ + if (sinkOutputNode_ == nullptr) { // init after set sinkoutput + TriggerCallback(INIT_DEVICE_RESULT, sinkInfo_.deviceName, ERROR); + return ERR_ILLEGAL_STATE; + } + + if (IsInit()) { + AUDIO_INFO_LOG("deinit:%{public}s before reload injector renderer manager", sinkInfo.deviceName.c_str()); + DeinitInner(false, true); + } + hpaeSignalProcessThread_ = std::make_unique(); + auto request = [this, sinkInfo, isReload]() { + AUDIO_INFO_LOG("reload injector renderer manager, deviceName %{public}s", sinkInfo.deviceName.c_str()); + for (const auto &it : sinkInputNodeMap_) { + TriggerStreamState(it.first, it.second); + DisConnectInputSession(it.first); + } + sinkInfo_ = sinkInfo; + InitManager(isReload); + AUDIO_INFO_LOG("init device:%{public}s manager end", sinkInfo.deviceName.c_str()); + for (const auto &it : sinkInputNodeMap_) { + ConnectInputSession(it.first); + } + }; + SendRequest(request, __func__); + hpaeSignalProcessThread_->ActivateThread(shared_from_this()); + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::SetLoudnessGain(uint32_t sessionId, float loudnessGain) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +void HpaeInjectorRendererManager::SendRequest(Request &&request, const std::string &funcName, bool isInit) +{ + if (!isInit && !IsInit()) { + AUDIO_ERR_LOG("HpaeOffloadRendererManager not init, %{public}s excute failed", funcName.c_str()); + return; + } + hpaeNoLockQueue_.PushRequest(std::move(request)); + if (hpaeSignalProcessThread_ == nullptr) { + AUDIO_ERR_LOG("hpaeSignalProcessThread_ is nullptr, %{public}s excute failed", funcName.c_str()); + HpaeMessageQueueMonitor::ReportMessageQueueException(HPAE_OFFLOAD_MANAGER_TYPE, funcName, "thread is nullptr"); + return; + } + hpaeSignalProcessThread_->Notify(); +} + +int32_t HpaeInjectorRendererManager::SetSinkVirtualOutputNode( + const std::shared_ptr &sinkVirtualOutputNode) +{ + // should set sinkoutputnode before init + sinkOutputNode_ = sinkVirtualOutputNode; + return SUCCESS; +} + +void HpaeInjectorRendererManager::InitManager(bool isReload) +{ + AUDIO_INFO_LOG("init devicename:%{public}s", sinkInfo_.deviceName.c_str()); + if (sinkOutputNode_ == nullptr) { // init after set sinkoutput + TriggerCallback(INIT_DEVICE_RESULT, sinkInfo_.deviceName, ERROR); + return; + } + HpaeNodeInfo nodeInfo = sinkOutputNode_ ->GetNodeInfo(); + sceneCluster_ = std::make_shared(nodeInfo, sinkInfo_); + int32_t ret = sinkOutputNode_->RenderSinkInit(); + isInit_.store(ret == SUCCESS); + AUDIO_INFO_LOG("HpaeInjectorRendererManager init %{public}s", ret == SUCCESS ? "success" : "fail"); + TriggerCallback(isReload ? RELOAD_AUDIO_SINK_RESULT : INIT_DEVICE_RESULT, sinkInfo_.deviceName, ret); +} + +int32_t HpaeInjectorRendererManager::CreateInputSession(const HpaeStreamInfo &streamInfo) +{ + Trace trace("[" + std::to_string(streamInfo.sessionId) + "]HpaeInjectorRendererManager::CreateInputSession"); + HpaeNodeInfo nodeInfo; + nodeInfo.channels = streamInfo.channels; + nodeInfo.format = streamInfo.format; + nodeInfo.frameLen = streamInfo.frameLen; + nodeInfo.streamType = streamInfo.streamType; + nodeInfo.sessionId = streamInfo.sessionId; + nodeInfo.samplingRate = static_cast(streamInfo.samplingRate); + nodeInfo.customSampleRate = streamInfo.customSampleRate; + nodeInfo.sceneType = TransStreamTypeToSceneType(streamInfo.streamType); + nodeInfo.effectInfo = streamInfo.effectInfo; + nodeInfo.historyFrameCount = 0; + nodeInfo.statusCallback = weak_from_this(); + nodeInfo.deviceClass = sinkInfo_.deviceClass; + nodeInfo.deviceNetId = sinkInfo_.deviceNetId; + sinkInputNodeMap_[streamInfo.sessionId] = std::make_shared(nodeInfo); + + return SUCCESS; +} + +void HpaeInjectorRendererManager::DeleteInputSession(const uint32_t &sessionId) +{ + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::DeleteInputSession"); + DisConnectInputSession(sessionId); + sinkInputNodeMap_.erase(sessionId); + sessionNodeMap_.erase(sessionId); +} + +int32_t HpaeInjectorRendererManager::ConnectInputSession(const uint32_t &sessionId) +{ + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::ConnectInputSession"); + CHECK_AND_RETURN_RET_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), ERR_INVALID_PARAM, + "connect fail, session %{public}u not found", sessionId); + CHECK_AND_RETURN_RET(sinkInputNodeMap_[sessionId]->GetState() != HPAE_SESSION_RUNNING, SUCCESS); + sinkOutputNode_->Connect(sceneCluster_); + sceneCluster_->Connect(sinkInputNodeMap_[sessionId]); + if (sinkOutputNode_->GetState() != STREAM_MANAGER_RUNNING && !isSuspend_) { + sinkOutputNode_->RenderSinkStart(); + } + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::DisConnectInputSession(const uint32_t &sessionId) +{ + Trace trace("[" + std::to_string(sessionId) + "]HpaeInjectorRendererManager::DisConnectInputSession"); + CHECK_AND_RETURN_RET_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), ERR_INVALID_PARAM, + "disconnect fail, session %{public}u not found", sessionId); + CHECK_AND_RETURN_RET(sinkInputNodeMap_[sessionId]->GetState() != HPAE_SESSION_RUNNING, SUCCESS); + sceneCluster_->DisConnect(sinkInputNodeMap_[sessionId]); + + if (sceneCluster_->GetConnectSinkInputNum() == 0) { + sinkOutputNode_->DisConnect(sceneCluster_); + sinkOutputNode_->RenderSinkStop(); + } + return SUCCESS; +} + +void HpaeInjectorRendererManager::MoveStreamSync(uint32_t sessionId, const std::string &sinkName) +{ + if (!SafeGetMap(sinkInputNodeMap_, sessionId)) { + AUDIO_ERR_LOG("[StartMove] session:%{public}u failed,can not find session,move %{public}s --> %{public}s", + sessionId, sinkInfo_.deviceName.c_str(), sinkName.c_str()); + TriggerCallback(MOVE_SESSION_FAILED, HPAE_STREAM_CLASS_TYPE_PLAY, sessionId, MOVE_SINGLE, sinkName); + HpaeStreamMoveMonitor::ReportStreamMoveException(0, sessionId, HPAE_STREAM_CLASS_TYPE_PLAY, + sinkInfo_.deviceName, sinkName, "not find session node"); + return; + } + + if (sinkName.empty()) { + AUDIO_ERR_LOG("[StartMove] session:%{public}u failed,sinkName is empty", sessionId); + TriggerCallback(MOVE_SESSION_FAILED, HPAE_STREAM_CLASS_TYPE_PLAY, sessionId, MOVE_SINGLE, sinkName); + HpaeStreamMoveMonitor::ReportStreamMoveException(sinkInputNodeMap_[sessionId]->GetAppUid(), sessionId, + HPAE_STREAM_CLASS_TYPE_PLAY, sinkInfo_.deviceName, sinkName, "sinkName is empty"); + return; + } + + AUDIO_INFO_LOG("[StartMove] session: %{public}u,sink [%{public}s] --> [%{public}s]", + sessionId, sinkInfo_.deviceName.c_str(), sinkName.c_str()); + std::shared_ptr inputNode = sinkInputNodeMap_[sessionId]; + DeleteInputSession(sessionId); + std::string name = sinkName; + TriggerCallback(MOVE_SINK_INPUT, inputNode, name); +} + +void HpaeInjectorRendererManager::MoveAllStreamToNewSink(const std::string &sinkName, + const std::vector& moveIds, MoveSessionType moveType) +{ + Trace trace("HpaeInjectorRendererManager::MoveAllStreamToNewSink[" + sinkName + "]"); + AUDIO_INFO_LOG("MoveAllStreamToNewSink[%{public}s]", sinkName.c_str()); + std::string name = sinkName; + std::vector> sinkInputs; + std::vector sessionIds; + std::string idStr; + for (const auto &it : sinkInputNodeMap_) { + if (moveType == MOVE_ALL || std::find(moveIds.begin(), moveIds.end(), it.first) != moveIds.end()) { + sinkInputs.emplace_back(it.second); + sessionIds.emplace_back(it.first); + idStr.append("[").append(std::to_string(it.first)).append("],"); + } + } + for (const auto &it : sessionIds) { + DeleteInputSession(it); + } + HILOG_COMM_INFO("[StartMove] session:%{public}s to sink name:%{public}s, move type:%{public}d", + idStr.c_str(), name.c_str(), moveType); + + if (moveType == MOVE_ALL) { + TriggerSyncCallback(MOVE_ALL_SINK_INPUT, sinkInputs, name, moveType); + } else { + TriggerCallback(MOVE_ALL_SINK_INPUT, sinkInputs, name, moveType); + } +} + +bool HpaeInjectorRendererManager::SetSessionFade(uint32_t sessionId, IOperation operation) +{ + CHECK_AND_RETURN_RET_LOG(SafeGetMap(sinkInputNodeMap_, sessionId), false, + "SetSessionFade not find session %{public}u", sessionId); + std::shared_ptr sessionGainNode = sceneCluster_->GetGainNodeById(sessionId); + if (sessionGainNode == nullptr) { + AUDIO_ERR_LOG("SetSessionFade not find gain node for session %{public}u", sessionId); + if (operation != OPERATION_STARTED) { + HpaeSessionState state = operation == OPERATION_STOPPED ? HPAE_SESSION_STOPPED : HPAE_SESSION_PAUSED; + SetSessionState(sessionId, state); + TriggerCallback(UPDATE_STATUS, HPAE_STREAM_CLASS_TYPE_PLAY, sessionId, state, operation); + } + return false; + } + AUDIO_INFO_LOG("get gain node of session %{public}d operation %{public}d.", sessionId, operation); + if (operation != OPERATION_STARTED) { + HpaeSessionState state = operation == OPERATION_STOPPED ? HPAE_SESSION_STOPPING : HPAE_SESSION_PAUSING; + SetSessionState(sessionId, state); + } + sessionGainNode->SetFadeState(operation); + return true; +} \ No newline at end of file diff --git a/services/audio_engine/node/include/hpae_virtual_process_cluster.h b/services/audio_engine/node/include/hpae_virtual_process_cluster.h new file mode 100644 index 0000000000..cacad74c60 --- /dev/null +++ b/services/audio_engine/node/include/hpae_virtual_process_cluster.h @@ -0,0 +1,52 @@ +/* + * 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 HPAE_VIRTUAL_PROCESS_CLUSTER_H +#define HPAE_VIRTUAL_PROCESS_CLUSTER_H +#include "hpae_mixer_node.h" +#include "hpae_audio_format_converter_node.h" +#include "hpae_gain_node.h" + +namespace OHOS { +namespace AudioStandard { +namespace HPAE { +class HpaeVirtualProcessCluster : public OutputNode, public InputNode { +public: + HpaeVirtualProcessCluster(HpaeNodeInfo nodeInfo, HpaeSinkInfo &sinkInfo); + virtual ~HpaeVirtualProcessCluster(); + virtual void DoProcess() override; + virtual bool Reset() override; + virtual bool ResetAll() override; + std::shared_ptr GetSharedInstance() override; + OutputPort *GetOutputPort() override; + void Connect(const std::shared_ptr> &preNode) override; + void DisConnect(const std::shared_ptr> &preNode) override; + int32_t SetupAudioLimiter(); + + size_t GetConnectSinkInputNum(); + std::shared_ptr GetGainNodeById(const uint32_t &sessionId); +private: + void CreateGainNode(uint32_t sessionId, const HpaeNodeInfo &preNodeInfo); + void CreateConverterNode(uint32_t sessionId, const HpaeNodeInfo &preNodeInfo); + + std::shared_ptr mixerNode_ = nullptr; + std::unordered_map> idConverterMap_; + std::unordered_map> idGainMap_; + HpaeSinkInfo sinkInfo_; +}; +} // namespace HPAE +} // namespace AudioStandard +} // namespace OHOS +#endif // HPAE_VIRTUAL_PROCESS_CLUSTER_H \ No newline at end of file diff --git a/services/audio_engine/node/src/hpae_virtual_process_cluster.cpp b/services/audio_engine/node/src/hpae_virtual_process_cluster.cpp new file mode 100644 index 0000000000..dc316fe77f --- /dev/null +++ b/services/audio_engine/node/src/hpae_virtual_process_cluster.cpp @@ -0,0 +1,139 @@ +/* + * 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 LOG_TAG +#define LOG_TAG "HpaeVirtualProcessCluster" +#endif + +#include "hpae_virtual_process_cluster.h" + +#include +#include "audio_engine_log.h" +#include "audio_errors.h" +#include "audio_utils.h" +#include "hpae_node_common.h" + +namespace OHOS { +namespace AudioStandard { +namespace HPAE { + +HpaeVirtualProcessCluster::HpaeVirtualProcessCluster(HpaeNodeInfo nodeInfo, HpaeSinkInfo &sinkInfo) + : HpaeNode(nodeInfo), mixerNode_(std::make_shared(nodeInfo)) +{ +#ifdef ENABLE_HIDUMP_DFX + SetNodeName("HpaeVirtualProcessCluster"); +#endif +} + +HpaeVirtualProcessCluster::~HpaeVirtualProcessCluster() +{ + AUDIO_INFO_LOG("Virtual process cluster destroyed, processor scene type is %{public}d", GetSceneType()); + Reset(); +#ifdef ENABLE_HIDUMP_DFX + AUDIO_INFO_LOG("NodeId: %{public}u NodeName: %{public}s destructed.", + GetNodeId(), GetNodeName().c_str()); +#endif +} + +void HpaeVirtualProcessCluster::DoProcess() +{ + mixerNode_->DoProcess(); +} + +bool HpaeVirtualProcessCluster::Reset() +{ + mixerNode_->Reset(); + return true; +} + +bool HpaeVirtualProcessCluster::ResetAll() +{ + return mixerNode_->ResetAll(); +} + +std::shared_ptr HpaeVirtualProcessCluster::GetSharedInstance() +{ + return mixerNode_; +} + +OutputPort *HpaeVirtualProcessCluster::GetOutputPort() +{ + return mixerNode_->GetOutputPort(); +} + +void HpaeVirtualProcessCluster::Connect(const std::shared_ptr> &preNode) +{ + HpaeNodeInfo sinkInputNodeInfo = preNode->GetNodeInfo(); + uint32_t sessionId = sinkInputNodeInfo.sessionId; + CreateGainNode(sessionId, sinkInputNodeInfo); + CreateConverterNode(sessionId, sinkInputNodeInfo); + + mixerNode_->Connect(idGainMap_[sessionId]); + idGainMap_[sessionId]->Connect(idConverterMap_[sessionId]); + idConverterMap_[sessionId]->Connect(preNode); + + mixerNode_->EnableProcess(true); +} + +void HpaeVirtualProcessCluster::DisConnect(const std::shared_ptr> &preNode) +{ + HpaeNodeInfo sinkInputNodeInfo = preNode->GetNodeInfo(); + uint32_t sessionId = sinkInputNodeInfo.sessionId; + if (SafeGetMap(idConverterMap_, sessionId)) { + idConverterMap_[sessionId]->DisConnect(preNode); + idGainMap_[sessionId]->DisConnect(idConverterMap_[sessionId]); + mixerNode_->DisConnect(idGainMap_[sessionId]); + + idConverterMap_.erase(sessionId); + idGainMap_.erase(sessionId); + AUDIO_INFO_LOG("Process DisConnect Exist converterNode preOutNum is %{public}zu", mixerNode_->GetPreOutNum()); + } + if (mixerNode_->GetPreOutNum() == 0) { // maybe not nessary + mixerNode_->EnableProcess(false); + AUDIO_DEBUG_LOG("Set mixerNode EnableProcess false"); + } +} + +int32_t HpaeVirtualProcessCluster::SetupAudioLimiter() +{ + return SUCCESS; +} + +void HpaeVirtualProcessCluster::CreateGainNode(uint32_t sessionId, const HpaeNodeInfo &preNodeInfo) +{ + CHECK_AND_RETURN(!SafeGetMap(idGainMap_, sessionId)); + HpaeNodeInfo gainNodeInfo = preNodeInfo; + idGainMap_[sessionId] = std::make_shared(gainNodeInfo); +} + +void HpaeVirtualProcessCluster::CreateConverterNode(uint32_t sessionId, const HpaeNodeInfo &preNodeInfo) +{ + CHECK_AND_RETURN(!SafeGetMap(idConverterMap_, sessionId)); + HpaeNodeInfo gainNodeInfo = preNodeInfo; + idConverterMap_[sessionId] = std::make_shared(gainNodeInfo, GetNodeInfo()); +} + +size_t HpaeVirtualProcessCluster::GetConnectSinkInputNum() +{ + return idConverterMap_.size(); // todo: not be converter num, should be mixernode input stream num +} + +std::shared_ptr HpaeVirtualProcessCluster::GetGainNodeById(const uint32_t &sessionId) +{ + return SafeGetMap(idGainMap_, sessionId); +} +} // namespace HPAE +} // namespace AudioStandard +} // namespace OHOS \ No newline at end of file -- Gitee From 4823f66bbde339b3114b9573ec4b3dc24750c828 Mon Sep 17 00:00:00 2001 From: Charles Date: Sat, 13 Sep 2025 18:33:14 +0800 Subject: [PATCH 3/5] proaudio inject Signed-off-by: Charles --- .../include/hpae_injector_renderer_manager.h | 107 ++++++++++++++++++ .../src/hpae_injector_renderer_manager.cpp | 57 +++++++++- 2 files changed, 163 insertions(+), 1 deletion(-) diff --git a/services/audio_engine/manager/include/hpae_injector_renderer_manager.h b/services/audio_engine/manager/include/hpae_injector_renderer_manager.h index 5dd09178ce..c0d1eb3291 100644 --- a/services/audio_engine/manager/include/hpae_injector_renderer_manager.h +++ b/services/audio_engine/manager/include/hpae_injector_renderer_manager.h @@ -12,3 +12,110 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#ifndef HPAE_INJECTOR_RENDER_MANAGER_H +#define HPAE_INJECTOR_RENDER_MANAGER_H +#include +#include +#include +#include +#include +#include "hpae_signal_process_thread.h" +#include "hpae_sink_virtual_output_node.h" +#include "hpae_virtual_process_cluster.h" +#include "hpae_msg_channel.h" +#include "hpae_no_lock_queue.h" +#include "i_hpae_renderer_manager.h" + +namespace OHOS { +namespace AudioStandard { +namespace HPAE { +class HpaeInjectorRendererManager : public IHpaeRendererManager { +public: + HpaeInjectorRendererManager(HpaeSinkInfo &sinkInfo); + virtual ~HpaeInjectorRendererManager(); + int32_t CreateStream(const HpaeStreamInfo &streamInfo) override; + int32_t DestroyStream(uint32_t sessionId) override; + + int32_t Start(uint32_t sessionId) override; + int32_t Pause(uint32_t sessionId) override; + int32_t Flush(uint32_t sessionId) override; + int32_t Drain(uint32_t sessionId) override; + int32_t Stop(uint32_t sessionId) override; + int32_t Release(uint32_t sessionId) override; + int32_t MoveStream(uint32_t sessionId, const std::string &sinkName) override; + int32_t MoveAllStream(const std::string &sinkName, const std::vector &sessionIds, + MoveSessionType moveType = MOVE_ALL) override; + int32_t SuspendStreamManager(bool isSuspend) override; + int32_t SetMute(bool isMute) override; + void Process() override; + void HandleMsg() override; + int32_t Init(bool isReload = false) override; + int32_t DeInit(bool isMoveDefault = false) override; + bool IsInit() override; + bool IsRunning(void) override; + bool IsMsgProcessing() override; + bool DeactivateThread() override; + int32_t SetClientVolume(uint32_t sessionId, float volume) override; + int32_t SetRate(uint32_t sessionId, int32_t rate) override; + int32_t SetAudioEffectMode(uint32_t sessionId, int32_t effectMode) override; + int32_t GetAudioEffectMode(uint32_t sessionId, int32_t &effectMode) override; + int32_t SetPrivacyType(uint32_t sessionId, int32_t privacyType) override; + int32_t GetPrivacyType(uint32_t sessionId, int32_t &privacyType) override; + int32_t RegisterWriteCallback(uint32_t sessionId, const std::weak_ptr &callback) override; + int32_t RegisterReadCallback(uint32_t sessionId, const std::weak_ptr &callback) override; + + size_t GetWritableSize(uint32_t sessionId) override; + int32_t UpdateSpatializationState(uint32_t sessionId, bool spatializationEnabled, + bool headTrackingEnabled) override; + int32_t UpdateMaxLength(uint32_t sessionId, uint32_t maxLength) override; + std::vector GetAllSinkInputsInfo() override; + int32_t GetSinkInputInfo(uint32_t sessionId, HpaeSinkInputInfo &sinkInputInfo) override; + int32_t RefreshProcessClusterByDevice() override; + HpaeSinkInfo GetSinkInfo() override; + + int32_t AddNodeToSink(const std::shared_ptr &node) override; + int32_t AddAllNodesToSink( + const std::vector> &sinkInputs, bool isConnect) override; + + void OnNodeStatusUpdate(uint32_t sessionId, IOperation operation) override; + void OnFadeDone(uint32_t sessionId, IOperation operation) override; + void OnNotifyQueue() override; + std::string GetThreadName() override; + int32_t DumpSinkInfo() override; + int32_t ReloadRenderManager(const HpaeSinkInfo &sinkInfo, bool isReload = false) override; + std::string GetDeviceHDFDumpInfo() override; + int32_t SetLoudnessGain(uint32_t sessionId, float loudnessGain) override; + int32_t SetSinkVirtualOutputNode(const std::shared_ptr &sinkVirtualOutputNode) override; +private: + void SendRequest(Request &&request, const std::string &funcName, bool isInit = false); + void InitManager(bool isReload = false); + int32_t CreateInputSession(const HpaeStreamInfo &streamInfo); + int32_t ConnectInputSession(const uint32_t &sessionId); + int32_t DisConnectInputSession(const uint32_t &sessionId); + void DeleteInputSession(const uint32_t &sessionId); + void MoveStreamSync(uint32_t sessionId, const std::string &sinkName); + void MoveAllStreamToNewSink(const std::string &sinkName, const std::vector& moveIds, + MoveSessionType moveType); + void AddSingleNodeToSink(const std::shared_ptr &node, bool isConnect = true); + bool SetSessionFade(uint32_t sessionId, IOperation operation); + void SetSessionState(uint32_t sessionId, HpaeSessionState state); + void TriggerStreamState(uint32_t sessionId, const std::shared_ptr &inputNode); + void DeinitInner(bool isMoveDefault, bool fromReload = false); + bool CheckIsStreamRunning(); +private: + std::shared_ptr sinkOutputNode_ = nullptr; + std::shared_ptr sceneCluster_ = nullptr; + std::unordered_map> sinkInputNodeMap_; + std::unordered_map sessionNodeMap_; + + HpaeNoLockQueue hpaeNoLockQueue_; + std::unique_ptr hpaeSignalProcessThread_ = nullptr; + std::atomic isInit_ = false; + HpaeSinkInfo sinkInfo_; + std::atomic isSuspend_ = false; +}; +} // namespace HPAE +} // namespace AudioStandard +} // namespace OHOS +#endif // HPAE_INJECTOR_RENDER_MANAGER_H \ No newline at end of file diff --git a/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp b/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp index 4551d1f9ee..f243fc76c5 100644 --- a/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp +++ b/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp @@ -13,6 +13,22 @@ * limitations under the License. */ +#ifndef LOG_TAG +#define LOG_TAG "HpaeInjectorRendererManager" +#endif + +#include "hpae_injector_renderer_manager.h" +#include "audio_errors.h" +#include "audio_stream_info.h" +#include "audio_utils.h" +#include "hpae_node_common.h" +#include "hpae_message_queue_monitor.h" +#include "hpae_stream_move_monitor.h" +#include "audio_engine_log.h" + +namespace OHOS { +namespace AudioStandard { +namespace HPAE { HpaeInjectorRendererManager::HpaeInjectorRendererManager(HpaeSinkInfo &sinkInfo) : hpaeNoLockQueue_(CURRENT_REQUEST_COUNT), sinkInfo_(sinkInfo) {} @@ -481,6 +497,12 @@ int32_t HpaeInjectorRendererManager::ReloadRenderManager(const HpaeSinkInfo &sin return SUCCESS; } +std::string HpaeInjectorRendererManager::GetDeviceHDFDumpInfo() +{ + // todo : hidump info + return ""; +} + int32_t HpaeInjectorRendererManager::SetLoudnessGain(uint32_t sessionId, float loudnessGain) { AUDIO_ERR_LOG("Unsupported operation"); @@ -661,4 +683,37 @@ bool HpaeInjectorRendererManager::SetSessionFade(uint32_t sessionId, IOperation } sessionGainNode->SetFadeState(operation); return true; -} \ No newline at end of file +} + +void HpaeInjectorRendererManager::SetSessionState(uint32_t sessionId, HpaeSessionState state) +{ + sessionNodeMap_[sessionId].state = state; + sinkInputNodeMap_[sessionId]->SetState(state); +} + +void HpaeInjectorRendererManager::TriggerStreamState(uint32_t sessionId, const std::shared_ptr &inputNode) +{ + HpaeSessionState inputState = inputNode->GetState(); + if (inputState == HPAE_SESSION_STOPPING || inputState == HPAE_SESSION_PAUSING) { + HpaeSessionState state = inputState == HPAE_SESSION_PAUSING ? HPAE_SESSION_PAUSED : HPAE_SESSION_STOPPED; + IOperation operation = inputState == HPAE_SESSION_PAUSING ? OPERATION_PAUSED : OPERATION_STOPPED; + SetSessionState(sessionId, state); + inputNode->SetState(state); + TriggerCallback(UPDATE_STATUS, HPAE_STREAM_CLASS_TYPE_PLAY, sessionId, state, operation); + } +} + +bool HpaeInjectorRendererManager::CheckIsStreamRunning() +{ + bool isRunning = false; + for (const auto& it : sessionNodeMap_) { + if (it.second.state == HPAE_SESSION_RUNNING) { + isRunning = true; + break; + } + } + return isRunning; +} +} // namespace HPAE +} // namespace AudioStandard +} // namespace OHOS \ No newline at end of file -- Gitee From a6a9bbda1464ac70c5f0a1726158e7ecfb45a357 Mon Sep 17 00:00:00 2001 From: Charles Date: Sat, 13 Sep 2025 19:39:43 +0800 Subject: [PATCH 4/5] proaudio inject Signed-off-by: Charles --- .../manager/include/hpae_capturer_manager.h | 1 + .../manager/include/i_hpae_renderer_manager.h | 1 + .../manager/src/hpae_capturer_manager.cpp | 5 ++- .../audio_engine/manager/src/hpae_manager.cpp | 20 ++++----- .../src/hpae_virtual_capturer_manager.cpp | 8 ++-- .../audio_engine/node/src/hpae_mixer_node.cpp | 4 +- .../node/src/hpae_node_common.cpp | 12 +++--- .../src/hpae_sink_virtual_output_node.cpp | 41 ++++++++++++------- .../node/src/hpae_source_process_cluster.cpp | 24 ++++++----- 9 files changed, 66 insertions(+), 50 deletions(-) diff --git a/services/audio_engine/manager/include/hpae_capturer_manager.h b/services/audio_engine/manager/include/hpae_capturer_manager.h index 96cae18c02..2bfd6698dd 100644 --- a/services/audio_engine/manager/include/hpae_capturer_manager.h +++ b/services/audio_engine/manager/include/hpae_capturer_manager.h @@ -75,6 +75,7 @@ public: int32_t ReloadCaptureManager(const HpaeSourceInfo &sourceInfo, bool isReload = false) override; int32_t DumpSourceInfo() override; std::string GetDeviceHDFDumpInfo() override; + int32_t AddCaptureInjector(const std::shared_ptr> &sinkOutputNode, const SourceType &sourceType) override; int32_t RemoveCaptureInjector(const std::shared_ptr> &sinkOutputNode, diff --git a/services/audio_engine/manager/include/i_hpae_renderer_manager.h b/services/audio_engine/manager/include/i_hpae_renderer_manager.h index 99d78b886e..98d7b82261 100644 --- a/services/audio_engine/manager/include/i_hpae_renderer_manager.h +++ b/services/audio_engine/manager/include/i_hpae_renderer_manager.h @@ -22,6 +22,7 @@ #include "hpae_stream_manager.h" #include "hpae_dfx_tree.h" #include "hpae_co_buffer_node.h" +#include "hpae_sink_virtual_output_node.h" namespace OHOS { namespace AudioStandard { namespace HPAE { diff --git a/services/audio_engine/manager/src/hpae_capturer_manager.cpp b/services/audio_engine/manager/src/hpae_capturer_manager.cpp index 26f1281e05..b93ee38a43 100644 --- a/services/audio_engine/manager/src/hpae_capturer_manager.cpp +++ b/services/audio_engine/manager/src/hpae_capturer_manager.cpp @@ -104,6 +104,7 @@ int32_t HpaeCapturerManager::CreateOutputSession(const HpaeStreamInfo &streamInf if (sceneType != HPAE_SCENE_EFFECT_NONE && !SafeGetMap(sceneClusterMap_, sceneType)) { // todo: algorithm instance count control + HpaeNodeInfo nodeInfo = sourceInputClusterMap_[mainMicType_]->GetNodeInfo(); sceneClusterMap_[sceneType] = std::make_shared(nodeInfo); if (CaptureEffectCreate(sceneType, enhanceScene) != SUCCESS) { // sceneClusterMap_.erase(sceneType); @@ -1027,7 +1028,7 @@ int32_t HpaeCapturerManager::AddCaptureInjector(const std::shared_ptrConnectInjector(sinkOutputNode); }; @@ -1040,7 +1041,7 @@ int32_t HpaeCapturerManager::RemoveCaptureInjector(const std::shared_ptrDisConnectInjector(sinkOutputNode); }; diff --git a/services/audio_engine/manager/src/hpae_manager.cpp b/services/audio_engine/manager/src/hpae_manager.cpp index 309ab5f724..aa33ec0462 100644 --- a/services/audio_engine/manager/src/hpae_manager.cpp +++ b/services/audio_engine/manager/src/hpae_manager.cpp @@ -273,7 +273,7 @@ int32_t HpaeManager::ReloadRenderManager(const AudioModuleInfo &audioModuleInfo, sinkVirtualOutputNodeMap_[sinkInfo.sinkId] = sinkVirtualOutputNodeMap_[oldId]; HpaeNodeInfo nodeInfo; TransSinkInfoToNodeInfo(sinkInfo, rendererManagerMap_[audioModuleInfo.name], nodeInfo); - sinkVirtualOutputNodeMap_[sinInfo.sinkId]->ReloadNode(nodeInfo); + sinkVirtualOutputNodeMap_[sinkInfo.sinkId]->ReloadNode(nodeInfo); } rendererManagerMap_[audioModuleInfo.name]->ReloadRenderManager(sinkInfo, isReload); return SUCCESS; @@ -301,7 +301,7 @@ int32_t HpaeManager::CreateRendererManager(const AudioModuleInfo &audioModuleInf AUDIO_INFO_LOG("SetDefaultSink name: %{public}s", defaultSink_.c_str()); } - if (sinkInfo.deviceName == "virtual") { // todo : rewrite correct name + if (audioModuleInfo.name == "virtual") { // todo : rewrite correct name std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); HpaeNodeInfo nodeInfo; TransSinkInfoToNodeInfo(sinkInfo, rendererManager, nodeInfo); @@ -2563,7 +2563,7 @@ void HpaeManager::UpdateAudioPortInfo(const uint32_t &sinkPortIndex, const Audio CHECK_AND_RETURN_LOG(sinkIdSinkNameMap_.find(sinkPortIndex) != sinkIdSinkNameMap_.end(), "sinkPortIndex[%{public}u] not exit", sinkPortIndex); std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); - auto rendererManager = SaftGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); + auto rendererManager = SafeGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); CHECK_AND_RETURN_LOG(rendererManager, "sink[%{public}s] is in wrong state", sinkIdSinkNameMap_[sinkPortIndex].c_str()); HpaeSinkInfo sinkInfo; @@ -2574,7 +2574,7 @@ void HpaeManager::UpdateAudioPortInfo(const uint32_t &sinkPortIndex, const Audio auto sinkOutputNode = SafeGetMap(sinkVirtualOutputNodeMap_, sinkPortIndex); CHECK_AND_RETURN_LOG(sinkOutputNode, "reload injector failed, sinkOutputNode is null"); HpaeNodeInfo nodeInfo; - TransSinkInfoToNodeInfo(sinkInfo, rendererMnaager, nodeInfo); + TransSinkInfoToNodeInfo(sinkInfo, rendererManager, nodeInfo); sinkOutputNode->ReloadNode(nodeInfo); rendererManager->ReloadRenderManager(sinkInfo, true); }; @@ -2588,13 +2588,13 @@ void HpaeManager::AddCaptureInjector( CHECK_AND_RETURN_LOG(sinkIdSinkNameMap_.find(sinkPortIndex) != sinkIdSinkNameMap_.end(), "sinkPortIndex[%{public}u] not exit", sinkPortIndex); std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); - auto rendererManager = SaftGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); + auto rendererManager = SafeGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); CHECK_AND_RETURN_LOG(rendererManager, "sink[%{public}s] is in wrong state", sinkIdSinkNameMap_[sinkPortIndex].c_str()); CHECK_AND_RETURN_LOG(sourceIdSourceNameMap_.find(sourcePortIndex) != sourceIdSourceNameMap_.end(), "sourcePortIndex[%{public}u] not exit", sourcePortIndex); - auto capturerManager = SafeGetMap(sourceIdSourceNameMap_, sourceIdSourceNameMap_[sourcePortIndex]); - CHECK_AND_RETURN_LOG(rendererManager, "source[%{public}s] is in wrong state", + auto capturerManager = SafeGetMap(capturerManagerMap_, sourceIdSourceNameMap_[sourcePortIndex]); + CHECK_AND_RETURN_LOG(capturerManager, "source[%{public}s] is in wrong state", sourceIdSourceNameMap_[sourcePortIndex].c_str()); capturerManager->AddCaptureInjector(sinkVirtualOutputNodeMap_[sinkPortIndex], sourceType); }; @@ -2608,13 +2608,13 @@ void HpaeManager::RemoveCaptureInjector( CHECK_AND_RETURN_LOG(sinkIdSinkNameMap_.find(sinkPortIndex) != sinkIdSinkNameMap_.end(), "sinkPortIndex[%{public}u] not exit", sinkPortIndex); std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); - auto rendererManager = SaftGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); + auto rendererManager = SafeGetMap(rendererManagerMap_, sinkIdSinkNameMap_[sinkPortIndex]); CHECK_AND_RETURN_LOG(rendererManager, "sink[%{public}s] is in wrong state", sinkIdSinkNameMap_[sinkPortIndex].c_str()); CHECK_AND_RETURN_LOG(sourceIdSourceNameMap_.find(sourcePortIndex) != sourceIdSourceNameMap_.end(), "sourcePortIndex[%{public}u] not exit", sourcePortIndex); - auto capturerManager = SafeGetMap(sourceIdSourceNameMap_, sourceIdSourceNameMap_[sourcePortIndex]); - CHECK_AND_RETURN_LOG(rendererManager, "source[%{public}s] is in wrong state", + auto capturerManager = SafeGetMap(capturerManagerMap_, sourceIdSourceNameMap_[sourcePortIndex]); + CHECK_AND_RETURN_LOG(capturerManager, "source[%{public}s] is in wrong state", sourceIdSourceNameMap_[sourcePortIndex].c_str()); capturerManager->RemoveCaptureInjector(sinkVirtualOutputNodeMap_[sinkPortIndex], sourceType); }; diff --git a/services/audio_engine/manager/src/hpae_virtual_capturer_manager.cpp b/services/audio_engine/manager/src/hpae_virtual_capturer_manager.cpp index a5ce5c63c6..e35e907de9 100644 --- a/services/audio_engine/manager/src/hpae_virtual_capturer_manager.cpp +++ b/services/audio_engine/manager/src/hpae_virtual_capturer_manager.cpp @@ -322,15 +322,15 @@ void HpaeVirtualCapturerManager::SetSessionState(HpaeCaptureMoveInfo &streamInfo streamInfo.sourceOutputNode->SetState(capturerState); } -int32_t HpaeCapturerManager::AddCaptureInjector(const std::shared_ptr> &sinkOutputNode, - const SourceType &sourceType) +int32_t HpaeVirtualCapturerManager::AddCaptureInjector( + const std::shared_ptr> &sinkOutputNode, const SourceType &sourceType) { AUDIO_ERR_LOG("Unsupported operation"); return SUCCESS; } -int32_t HpaeCapturerManager::RemoveCaptureInjector(const std::shared_ptr> &sinkOutputNode, - const SourceType &sourceType) +int32_t HpaeVirtualCapturerManager::RemoveCaptureInjector( + const std::shared_ptr> &sinkOutputNode, const SourceType &sourceType) { AUDIO_ERR_LOG("Unsupported operation"); return SUCCESS; diff --git a/services/audio_engine/node/src/hpae_mixer_node.cpp b/services/audio_engine/node/src/hpae_mixer_node.cpp index 5bd640b15c..3470c3f996 100644 --- a/services/audio_engine/node/src/hpae_mixer_node.cpp +++ b/services/audio_engine/node/src/hpae_mixer_node.cpp @@ -66,7 +66,7 @@ void HpaeMixerNode::SetNodeInfo(HpaeNodeInfo& nodeInfo) HpaeNode::SetNodeInfo(nodeInfo); } -void HpaeCaptureEffectNode::ConnectWithInfo(const std::shared_ptr> &preNode, +void HpaeMixerNode::ConnectWithInfo(const std::shared_ptr> &preNode, HpaeNodeInfo &nodeInfo) { std::shared_ptr realPreNode = preNode->GetSharedInstance(nodeInfo); @@ -79,7 +79,7 @@ void HpaeCaptureEffectNode::ConnectWithInfo(const std::shared_ptr>& preNode, +void HpaeMixerNode::DisConnectWithInfo(const std::shared_ptr>& preNode, HpaeNodeInfo &nodeInfo) { CHECK_AND_RETURN_LOG(!inputStream_.CheckIfDisConnected(preNode->GetOutputPort(nodeInfo)), diff --git a/services/audio_engine/node/src/hpae_node_common.cpp b/services/audio_engine/node/src/hpae_node_common.cpp index 46e5ee3c0d..f7622f9c88 100644 --- a/services/audio_engine/node/src/hpae_node_common.cpp +++ b/services/audio_engine/node/src/hpae_node_common.cpp @@ -530,14 +530,14 @@ int32_t CheckSourceInfoFramelen(const HpaeSourceInfo &sourceInfo) void TransSinkInfoToNodeInfo(const HpaeSinkInfo &sinkInfo, const std::weak_ptr &statusCallback, HpaeNodeInfo &nodeInfo) { - nodeInfo.channels = sinkInfo_.channels; - nodeInfo.format = sinkInfo_.format; - nodeInfo.frameLen = sinkInfo_.frameLen; + nodeInfo.channels = sinkInfo.channels; + nodeInfo.format = sinkInfo.format; + nodeInfo.frameLen = sinkInfo.frameLen; nodeInfo.nodeId = 0; - nodeInfo.samplingRate = sinkInfo_.samplingRate; + nodeInfo.samplingRate = sinkInfo.samplingRate; nodeInfo.sceneType = HPAE_SCENE_EFFECT_OUT; - nodeInfo.deviceNetId = sinkInfo_.deviceNetId; - nodeInfo.deviceClass = sinkInfo_.deviceClass; + nodeInfo.deviceNetId = sinkInfo.deviceNetId; + nodeInfo.deviceClass = sinkInfo.deviceClass; nodeInfo.statusCallback = statusCallback; } } // namespace HPAE diff --git a/services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp b/services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp index 722bf9afa9..4fa198df2d 100644 --- a/services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp +++ b/services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License") + * 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 * @@ -28,7 +28,7 @@ namespace OHOS { namespace AudioStandard { namespace HPAE { -static constexpr uint32_t DEFAULT_RING_CACHE_NUM = 1; +static constexpr uint32_t DEFAULT_RING_BUFFER_NUM = 1; static constexpr uint32_t DEFAULT_FRAME_LEN_MS = 20; static constexpr uint32_t MS_PER_SECOND = 1000; @@ -47,7 +47,7 @@ HpaeSinkVirtualOutputNode::HpaeSinkVirtualOutputNode(HpaeNodeInfo &nodeInfo) ringCache_ = AudioRingCache::Create(GetRingCacheSize()); if (ringCache_ == nullptr) { AUDIO_ERR_LOG("ringCache create fail"); - } + } } HpaeSinkVirtualOutputNode::~HpaeSinkVirtualOutputNode() @@ -67,7 +67,7 @@ void HpaeSinkVirtualOutputNode::DoRenderProcess() OptResult result = ringCache_->Enqueue( {reinterpret_cast(outputData->GetPcmDataBuffer()), outputData->DataSize()}); - CHECK_AND_RETURN_LOG(retsult.ret == OPERATION_SUCCESS, "ringCache enqueue fail"); + CHECK_AND_RETURN_LOG(result.ret == OPERATION_SUCCESS, "ringCache enqueue fail"); } void HpaeSinkVirtualOutputNode::DoProcess() @@ -75,14 +75,15 @@ void HpaeSinkVirtualOutputNode::DoProcess() Trace trace("HpaeSinkVirtualOutputNode::DoProcess " + GetTraceInfo()); OptResult result = ringCache_->Dequeue( {reinterpret_cast(outputAudioBuffer_.GetPcmDataBuffer()), outputAudioBuffer_.DataSize()}); - CHECK_AND_RETURN_LOG(retsult.ret == OPERATION_SUCCESS, "ringCache dequeue fail"); + CHECK_AND_RETURN_LOG(result.ret == OPERATION_SUCCESS, "ringCache dequeue fail"); outputStream_.WriteDataToOutput(&outputAudioBuffer_); if (auto callback = GetNodeStatusCallback().lock()) { callback->OnNotifyQueue(); } } -int32_t HpaeSinkVirtualOutputNode::PeekAudioData(uint8_t **buffer, const size_t &bufferSize) +int32_t HpaeSinkVirtualOutputNode::PeekAudioData(uint8_t **buffer, const size_t &bufferSize, + AudioStreamInfo &audioStreamInfo) { Trace trace("HpaeSinkVirtualOutputNode::PeekAudioData" + GetTraceInfo()); std::lock_guard lock(mutex_); @@ -117,7 +118,17 @@ bool HpaeSinkVirtualOutputNode::ResetAll() return true; } -void HpaeSinkVirtualOutputNode::Connect(const std::shared_ptr> &preNode) override +std::shared_ptr HpaeSinkVirtualOutputNode::GetSharedInstance() +{ + return shared_from_this(); +} + +OutputPort *HpaeSinkVirtualOutputNode::GetOutputPort() +{ + return &outputStream_; +} + +void HpaeSinkVirtualOutputNode::Connect(const std::shared_ptr> &preNode) { inputStream_.Connect(preNode->GetSharedInstance(), preNode->GetOutputPort()); #ifdef ENABLE_HIDUMP_DFX @@ -127,7 +138,7 @@ void HpaeSinkVirtualOutputNode::Connect(const std::shared_ptr> &preNode) override +void HpaeSinkVirtualOutputNode::DisConnect(const std::shared_ptr> &preNode) { inputStream_.DisConnect(preNode->GetOutputPort()); #ifdef ENABLE_HIDUMP_DFX @@ -138,6 +149,11 @@ void HpaeSinkVirtualOutputNode::DisConnect(const std::shared_ptrResetBuffer(); } SetSinkState(STREAM_MANAGER_SUSPENDED); return SUCCESS; @@ -171,11 +187,6 @@ size_t HpaeSinkVirtualOutputNode::GetPreOutNum() return inputStream_.GetPreOutputNum(); } -StreamManagerState HpaeSinkVirtualOutputNode::GetSinkState(void) -{ - return state_; -} - int32_t HpaeSinkVirtualOutputNode::SetSinkState(StreamManagerState sinkState) { AUDIO_INFO_LOG("Sink[%{public}s] state change:[%{public}s]-->[%{public}s]", @@ -198,7 +209,7 @@ bool HpaeSinkVirtualOutputNode::GetIsReadFinished() return result.size != 0; } -int32_t HpaeSinkVirtualOutputNode::ReloadNode(hpaeNodeInfo nodeInfo) +int32_t HpaeSinkVirtualOutputNode::ReloadNode(HpaeNodeInfo nodeInfo) { std::lock_guard lock(mutex_); nodeInfo.nodeId = GetNodeId(); // not change nodeId diff --git a/services/audio_engine/node/src/hpae_source_process_cluster.cpp b/services/audio_engine/node/src/hpae_source_process_cluster.cpp index 986fe2a151..4f3446800c 100644 --- a/services/audio_engine/node/src/hpae_source_process_cluster.cpp +++ b/services/audio_engine/node/src/hpae_source_process_cluster.cpp @@ -26,7 +26,7 @@ namespace OHOS { namespace AudioStandard { namespace HPAE { HpaeSourceProcessCluster::HpaeSourceProcessCluster(HpaeNodeInfo& nodeInfo) // nodeInfo maybe sourceinputnode info - : HpaeNode(nodeInfo), captureEffectNode_(std::make_shared(nodeInfo)), + : HpaeNode(nodeInfo), captureEffectNode_(std::make_shared(nodeInfo)), mixerNode_(std::make_shared(nodeInfo)) { #ifdef ENABLE_HIDUMP_DFX @@ -110,8 +110,10 @@ std::shared_ptr HpaeSourceProcessCluster::GetSharedInstance(HpaeNodeIn OutputPort *HpaeSourceProcessCluster::GetOutputPort(HpaeNodeInfo &nodeInfo, bool isDisConnect) { std::string sourceOutputNodeKey = TransNodeInfoToStringKey(nodeInfo); - HpaeNodeInfo effectNodeInfo; - captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); + HpaeNodeInfo effectNodeInfo = mixerNode_->GetNodeInfo(); + if (captureEffectNode_ != nullptr) { + captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); + } std::string effectNodeKey = TransNodeInfoToStringKey(effectNodeInfo); AUDIO_INFO_LOG("sourceOutput:[%{public}s] effectNode:[%{public}s]", sourceOutputNodeKey.c_str(), effectNodeKey.c_str()); @@ -168,7 +170,7 @@ void HpaeSourceProcessCluster::DisConnectWithInfo(const std::shared_ptr>& preNode) { AUDIO_INFO_LOG("connect injector sinkOutputNode in processcluster"); - CHECK_AND_RETURN_(preNode != nullptr, "pre sinkOutputNode is nullptr"); + CHECK_AND_RETURN_LOG(preNode != nullptr, "pre sinkOutputNode is nullptr"); HpaeNodeInfo sinkNodeInfo = preNode->GetNodeInfo(); HpaeNodeInfo mixerNodeInfo = mixerNode_->GetNodeInfo(); if (CheckHpaeNodeInfoIsSame(sinkNodeInfo, mixerNodeInfo)) { @@ -176,7 +178,7 @@ void HpaeSourceProcessCluster::ConnectInjector(const std::shared_ptrConnect(preNode); } else { injectorFmtConverterNodeMap_[preNode] = - std::make_shared(HpaeAudioFormatConverterNode)(sinkNodeInfo, mixerNodeInfo); + std::make_shared(sinkNodeInfo, mixerNodeInfo); mixerNode_->Connect(injectorFmtConverterNodeMap_[preNode]); injectorFmtConverterNodeMap_[preNode]->Connect(preNode); } @@ -185,14 +187,14 @@ void HpaeSourceProcessCluster::ConnectInjector(const std::shared_ptr>& preNode) { AUDIO_INFO_LOG("disconnect injector sinkOutputNode in processcluster"); - CHECK_AND_RETURN_(preNode != nullptr, "pre sinkOutputNode is nullptr"); + CHECK_AND_RETURN_LOG(preNode != nullptr, "pre sinkOutputNode is nullptr"); HpaeNodeInfo sinkNodeInfo = preNode->GetNodeInfo(); HpaeNodeInfo mixerNodeInfo = mixerNode_->GetNodeInfo(); if (CheckHpaeNodeInfoIsSame(sinkNodeInfo, mixerNodeInfo)) { AUDIO_INFO_LOG("Specification of sinkOutputNode is same with mixerNode"); mixerNode_->DisConnect(preNode); } else { - injectorFmtConverterNodeMap_[preNode]->Connect(preNode); + injectorFmtConverterNodeMap_[preNode]->DisConnect(preNode); mixerNode_->DisConnect(injectorFmtConverterNodeMap_[preNode]); injectorFmtConverterNodeMap_.erase(preNode); } @@ -200,11 +202,11 @@ void HpaeSourceProcessCluster::DisConnectInjector(const std::shared_ptrGetCapturerEffectConfig(nodeInfo, type); + if (captureEffectNode_ == nullptr) { + nodeInfo = mixerNode_->GetNodeInfo(); + return true; } - nodeInfo = mixerNode_->GetNodeInfo(); - return true; + return captureEffectNode_->GetCapturerEffectConfig(nodeInfo, type); } size_t HpaeSourceProcessCluster::GetOutputPortNum() -- Gitee From a0711e7579147b5b234f72f87a6639b84c04c87a Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 17 Sep 2025 15:03:21 +0800 Subject: [PATCH 5/5] proaudio inject Signed-off-by: Charles --- .../manager/src/hpae_capturer_manager.cpp | 12 +- .../src/hpae_injector_renderer_manager.cpp | 32 +-- .../audio_engine/manager/src/hpae_manager.cpp | 8 +- .../manager/src/i_hpae_renderer_manager.cpp | 2 +- .../node/include/hpae_capture_effect_node.h | 4 +- .../node/include/hpae_node_common.h | 1 + .../include/hpae_source_process_cluster.h | 1 + .../include/hpae_virtual_process_cluster.h | 5 +- .../node/src/hpae_node_common.cpp | 6 + .../node/src/hpae_source_process_cluster.cpp | 60 ++-- .../node/src/hpae_virtual_process_cluster.cpp | 2 +- services/audio_engine/test/unittest/BUILD.gn | 42 +++ .../manager/hpae_capturer_manager_test.cpp | 41 +++ .../unittest/manager/hpae_manager_test.cpp | 50 +++- .../manager/hpae_render_manager_test.cpp | 198 ++++++++++++++ .../unittest/node/hpae_mixer_node_test.cpp | 18 ++ .../hpae_sink_virtual_output_node_test.cpp | 257 ++++++++++++++++++ .../node/hpae_source_process_cluster_test.cpp | 96 ++++++- .../hpae_virtual_process_cluster_test.cpp | 254 +++++++++++++++++ test/BUILD.gn | 2 + 20 files changed, 1016 insertions(+), 75 deletions(-) create mode 100644 services/audio_engine/test/unittest/node/hpae_sink_virtual_output_node_test.cpp create mode 100644 services/audio_engine/test/unittest/node/hpae_virtual_process_cluster_test.cpp diff --git a/services/audio_engine/manager/src/hpae_capturer_manager.cpp b/services/audio_engine/manager/src/hpae_capturer_manager.cpp index b93ee38a43..fd1806d8dd 100644 --- a/services/audio_engine/manager/src/hpae_capturer_manager.cpp +++ b/services/audio_engine/manager/src/hpae_capturer_manager.cpp @@ -104,10 +104,15 @@ int32_t HpaeCapturerManager::CreateOutputSession(const HpaeStreamInfo &streamInf if (sceneType != HPAE_SCENE_EFFECT_NONE && !SafeGetMap(sceneClusterMap_, sceneType)) { // todo: algorithm instance count control - HpaeNodeInfo nodeInfo = sourceInputClusterMap_[mainMicType_]->GetNodeInfo(); - sceneClusterMap_[sceneType] = std::make_shared(nodeInfo); + HpaeNodeInfo clusterNodeInfo; + clusterNodeInfo.channels = sourceInfo_.channels; + clusterNodeInfo.format = sourceInfo_.format; + clusterNodeInfo.samplingRate = sourceInfo_.samplingRate; + clusterNodeInfo.frameLen = CaculateFrameLenByNodeInfo(nodeInfo); + clusterNodeInfo.statusCallback = weak_from_this(); + clusterNodeInfo.sourceBufferType = HPAE_SOURCE_BUFFER_TYPE_MIC; + sceneClusterMap_[sceneType] = std::make_shared(clusterNodeInfo); if (CaptureEffectCreate(sceneType, enhanceScene) != SUCCESS) { - // sceneClusterMap_.erase(sceneType); // not erase effect processcluster for inject AUDIO_WARNING_LOG("sceneType[%{public}u] create failed, not delete sceneCluster", sceneType); } @@ -884,7 +889,6 @@ void HpaeCapturerManager::AddSingleNodeToSource(const HpaeCaptureMoveInfo &moveI } if (CaptureEffectCreate(sceneType, enhanceScene) != SUCCESS) { AUDIO_WARNING_LOG("[FinishMove] session :%{public}u,create effect failed.", sessionId); - sceneClusterMap_.erase(sceneType); } if (moveInfo.sessionInfo.state == HPAE_SESSION_RUNNING) { diff --git a/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp b/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp index f243fc76c5..12f5ba62e1 100644 --- a/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp +++ b/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp @@ -35,7 +35,7 @@ HpaeInjectorRendererManager::HpaeInjectorRendererManager(HpaeSinkInfo &sinkInfo) HpaeInjectorRendererManager::~HpaeInjectorRendererManager() { - AUDIO_INFO_LOG("destructor offload renderer"); + AUDIO_INFO_LOG("destructor injector renderer"); if (isInit_.load()) { DeInit(); } @@ -226,6 +226,7 @@ void HpaeInjectorRendererManager::HandleMsg() int32_t HpaeInjectorRendererManager::Init(bool isReload) { // after set sinkoutputnode + CHECK_AND_RETURN_RET_LOG(sinkOutputNode_ != nullptr, ERR_INVALID_OPERATION, "init fail, sinkOutputNode is null"); hpaeSignalProcessThread_ = std::make_unique(); auto request = [this, isReload] { InitManager(isReload); @@ -375,6 +376,11 @@ std::vector HpaeInjectorRendererManager::GetAllSinkInputsInfo() int32_t HpaeInjectorRendererManager::GetSinkInputInfo(uint32_t sessionId, HpaeSinkInputInfo &sinkInputInfo) { + if (!SafeGetMap(sinkInputNodeMap_, sessionId)) { + return ERR_INVALID_OPERATION; + } + sinkInputInfo.nodeInfo = sinkInputNodeMap_[sessionId]->GetNodeInfo(); + sinkInputInfo.rendererSessionInfo = sessionNodeMap_[sessionId]; return SUCCESS; } @@ -386,7 +392,7 @@ int32_t HpaeInjectorRendererManager::RefreshProcessClusterByDevice() HpaeSinkInfo HpaeInjectorRendererManager::GetSinkInfo() { - return HpaeSinkInfo{}; + return sinkInfo_; } int32_t HpaeInjectorRendererManager::AddNodeToSink(const std::shared_ptr &node) @@ -414,7 +420,7 @@ void HpaeInjectorRendererManager::AddSingleNodeToSink(const std::shared_ptrGetState() == HPAE_SESSION_RUNNING) { ConnectInputSession(sessionId); } - AUDIO_INFO_LOG("[FinishMove] session:%{public}u to sink:offload", sessionId); + AUDIO_INFO_LOG("[FinishMove] session:%{public}u to sink:injector", sessionId); } int32_t HpaeInjectorRendererManager::AddAllNodesToSink( @@ -451,8 +457,8 @@ void HpaeInjectorRendererManager::OnFadeDone(uint32_t sessionId, IOperation oper void HpaeInjectorRendererManager::OnNotifyQueue() { + Trace trace("HpaeInjectorRendererManager::OnNotifyQueue"); CHECK_AND_RETURN_LOG(hpaeSignalProcessThread_, "HpaeInjectorRendererManager hpaeSignalProcessThread_ is nullptr"); - // Trace trace("HpaeInjectorRendererManager::OnNotifyQueue()"); hpaeSignalProcessThread_->Notify(); } @@ -492,7 +498,7 @@ int32_t HpaeInjectorRendererManager::ReloadRenderManager(const HpaeSinkInfo &sin ConnectInputSession(it.first); } }; - SendRequest(request, __func__); + SendRequest(request, __func__, true); hpaeSignalProcessThread_->ActivateThread(shared_from_this()); return SUCCESS; } @@ -512,15 +518,10 @@ int32_t HpaeInjectorRendererManager::SetLoudnessGain(uint32_t sessionId, float l void HpaeInjectorRendererManager::SendRequest(Request &&request, const std::string &funcName, bool isInit) { if (!isInit && !IsInit()) { - AUDIO_ERR_LOG("HpaeOffloadRendererManager not init, %{public}s excute failed", funcName.c_str()); + AUDIO_ERR_LOG("HpaeInjectorRendererManager not init, %{public}s excute failed", funcName.c_str()); return; } hpaeNoLockQueue_.PushRequest(std::move(request)); - if (hpaeSignalProcessThread_ == nullptr) { - AUDIO_ERR_LOG("hpaeSignalProcessThread_ is nullptr, %{public}s excute failed", funcName.c_str()); - HpaeMessageQueueMonitor::ReportMessageQueueException(HPAE_OFFLOAD_MANAGER_TYPE, funcName, "thread is nullptr"); - return; - } hpaeSignalProcessThread_->Notify(); } @@ -535,12 +536,8 @@ int32_t HpaeInjectorRendererManager::SetSinkVirtualOutputNode( void HpaeInjectorRendererManager::InitManager(bool isReload) { AUDIO_INFO_LOG("init devicename:%{public}s", sinkInfo_.deviceName.c_str()); - if (sinkOutputNode_ == nullptr) { // init after set sinkoutput - TriggerCallback(INIT_DEVICE_RESULT, sinkInfo_.deviceName, ERROR); - return; - } HpaeNodeInfo nodeInfo = sinkOutputNode_ ->GetNodeInfo(); - sceneCluster_ = std::make_shared(nodeInfo, sinkInfo_); + sceneCluster_ = std::make_shared(nodeInfo); int32_t ret = sinkOutputNode_->RenderSinkInit(); isInit_.store(ret == SUCCESS); AUDIO_INFO_LOG("HpaeInjectorRendererManager init %{public}s", ret == SUCCESS ? "success" : "fail"); @@ -691,7 +688,8 @@ void HpaeInjectorRendererManager::SetSessionState(uint32_t sessionId, HpaeSessio sinkInputNodeMap_[sessionId]->SetState(state); } -void HpaeInjectorRendererManager::TriggerStreamState(uint32_t sessionId, const std::shared_ptr &inputNode) +void HpaeInjectorRendererManager::TriggerStreamState(uint32_t sessionId, + const std::shared_ptr &inputNode) { HpaeSessionState inputState = inputNode->GetState(); if (inputState == HPAE_SESSION_STOPPING || inputState == HPAE_SESSION_PAUSING) { diff --git a/services/audio_engine/manager/src/hpae_manager.cpp b/services/audio_engine/manager/src/hpae_manager.cpp index aa33ec0462..635f3922fd 100644 --- a/services/audio_engine/manager/src/hpae_manager.cpp +++ b/services/audio_engine/manager/src/hpae_manager.cpp @@ -268,7 +268,7 @@ int32_t HpaeManager::ReloadRenderManager(const AudioModuleInfo &audioModuleInfo, sinkNameSinkIdMap_[audioModuleInfo.name] = sinkSourceIndex; } - if (sinkInfo.deviceName == "virtual") { // todo : rewrite correct name + if (sinkInfo.deviceName == "Virtual_Injector") { // todo : rewrite correct name std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); sinkVirtualOutputNodeMap_[sinkInfo.sinkId] = sinkVirtualOutputNodeMap_[oldId]; HpaeNodeInfo nodeInfo; @@ -301,7 +301,7 @@ int32_t HpaeManager::CreateRendererManager(const AudioModuleInfo &audioModuleInf AUDIO_INFO_LOG("SetDefaultSink name: %{public}s", defaultSink_.c_str()); } - if (audioModuleInfo.name == "virtual") { // todo : rewrite correct name + if (audioModuleInfo.name == "Virtual_Injector") { // todo : rewrite correct name std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); HpaeNodeInfo nodeInfo; TransSinkInfoToNodeInfo(sinkInfo, rendererManager, nodeInfo); @@ -597,7 +597,7 @@ void HpaeManager::AddPreferSinkForDefaultChange(bool isAdd, const std::string &s int32_t HpaeManager::CloseOutAudioPort(std::string sinkName) { std::unique_lock lock(sinkVirtualOutputNodeMapMutex_, std::defer_lock); - if (sinkName == "virtual") { + if (sinkName == "Virtual_Injector") { lock.lock(); } if (!SafeGetMap(rendererManagerMap_, sinkName)) { @@ -617,7 +617,7 @@ int32_t HpaeManager::CloseOutAudioPort(std::string sinkName) AddPreferSinkForDefaultChange(isChangeDefaultSink, sinkName); rendererManagerMap_[sinkName]->DeInit(sinkName != defaultSink_); if (sinkName != defaultSink_) { - if (sinkName == "virtual") { + if (sinkName == "Virtual_Injector") { sinkVirtualOutputNodeMap_.erase(sinkNameSinkIdMap_[sinkName]); } rendererManagerMap_.erase(sinkName); diff --git a/services/audio_engine/manager/src/i_hpae_renderer_manager.cpp b/services/audio_engine/manager/src/i_hpae_renderer_manager.cpp index ce8ff49eff..f81ae7e261 100644 --- a/services/audio_engine/manager/src/i_hpae_renderer_manager.cpp +++ b/services/audio_engine/manager/src/i_hpae_renderer_manager.cpp @@ -37,7 +37,7 @@ std::shared_ptr IHpaeRendererManager::CreateRendererManage } else if ((sinkInfo.deviceName.compare(0, DEVICE_NAME_INNER_CAP.length(), DEVICE_NAME_INNER_CAP) == 0) || sinkInfo.deviceName == DEVICE_NAME_CAST_INNER_CAP) { return std::make_shared(sinkInfo); - } else if (sinkInfo.deviceName == "virtual") { // todo : rewrite device name + } else if (sinkInfo.deviceName == "Virtual_Injector") { // todo : rewrite device name return std::make_shared(sinkInfo); } return std::make_shared(sinkInfo); diff --git a/services/audio_engine/node/include/hpae_capture_effect_node.h b/services/audio_engine/node/include/hpae_capture_effect_node.h index 8e872c3a05..ce42d35966 100644 --- a/services/audio_engine/node/include/hpae_capture_effect_node.h +++ b/services/audio_engine/node/include/hpae_capture_effect_node.h @@ -43,8 +43,8 @@ public: void ConnectWithInfo(const std::shared_ptr> &preNode, HpaeNodeInfo &nodeInfo) override; void DisConnectWithInfo(const std::shared_ptr> &preNode, HpaeNodeInfo &nodeInfo) override; - bool GetCapturerEffectConfig(HpaeNodeInfo& nodeInfo, HpaeSourceBufferType type = HPAE_SOURCE_BUFFER_TYPE_MIC); - int32_t CaptureEffectCreate(uint64_t sceneKeyCode, CaptureEffectAttr attr); + virtual bool GetCapturerEffectConfig(HpaeNodeInfo& nodeInfo, HpaeSourceBufferType type = HPAE_SOURCE_BUFFER_TYPE_MIC); + virtual int32_t CaptureEffectCreate(uint64_t sceneKeyCode, CaptureEffectAttr attr); int32_t CaptureEffectRelease(uint64_t sceneKeyCode); protected: HpaePcmBuffer *SignalProcess(const std::vector &inputs) override; diff --git a/services/audio_engine/node/include/hpae_node_common.h b/services/audio_engine/node/include/hpae_node_common.h index 380b95fa0b..f3914a6641 100644 --- a/services/audio_engine/node/include/hpae_node_common.h +++ b/services/audio_engine/node/include/hpae_node_common.h @@ -68,6 +68,7 @@ void TransStreamInfoToStreamDumpInfo(const std::unordered_map &dumpInfo); void TransSinkInfoToNodeInfo(const HpaeSinkInfo &sinkInfo, const std::weak_ptr &statusCallback, HpaeNodeInfo &nodeInfo); +size_t CaculateFrameLenByNodeInfo(HpaeNodeInfo &nodeInfo); } // namespace HPAE } // namespace AudioStandard } // namespace OHOS diff --git a/services/audio_engine/node/include/hpae_source_process_cluster.h b/services/audio_engine/node/include/hpae_source_process_cluster.h index b26390e253..fa658b4d32 100644 --- a/services/audio_engine/node/include/hpae_source_process_cluster.h +++ b/services/audio_engine/node/include/hpae_source_process_cluster.h @@ -52,6 +52,7 @@ public: bool IsEffectNodeValid(); // for ut test + uint32_t GetMixerNodeUseCount(); uint32_t GetCapturerEffectNodeUseCount(); uint32_t GetConverterNodeCount(); size_t GetPreOutNum(); diff --git a/services/audio_engine/node/include/hpae_virtual_process_cluster.h b/services/audio_engine/node/include/hpae_virtual_process_cluster.h index cacad74c60..5209c1642f 100644 --- a/services/audio_engine/node/include/hpae_virtual_process_cluster.h +++ b/services/audio_engine/node/include/hpae_virtual_process_cluster.h @@ -15,7 +15,7 @@ #ifndef HPAE_VIRTUAL_PROCESS_CLUSTER_H #define HPAE_VIRTUAL_PROCESS_CLUSTER_H -#include "hpae_mixer_node.h" +#include "hpae_mixer_node.h"\ #include "hpae_audio_format_converter_node.h" #include "hpae_gain_node.h" @@ -24,7 +24,7 @@ namespace AudioStandard { namespace HPAE { class HpaeVirtualProcessCluster : public OutputNode, public InputNode { public: - HpaeVirtualProcessCluster(HpaeNodeInfo nodeInfo, HpaeSinkInfo &sinkInfo); + HpaeVirtualProcessCluster(HpaeNodeInfo nodeInfo); virtual ~HpaeVirtualProcessCluster(); virtual void DoProcess() override; virtual bool Reset() override; @@ -44,7 +44,6 @@ private: std::shared_ptr mixerNode_ = nullptr; std::unordered_map> idConverterMap_; std::unordered_map> idGainMap_; - HpaeSinkInfo sinkInfo_; }; } // namespace HPAE } // namespace AudioStandard diff --git a/services/audio_engine/node/src/hpae_node_common.cpp b/services/audio_engine/node/src/hpae_node_common.cpp index f7622f9c88..0c3a426a86 100644 --- a/services/audio_engine/node/src/hpae_node_common.cpp +++ b/services/audio_engine/node/src/hpae_node_common.cpp @@ -29,6 +29,7 @@ static constexpr uint32_t DEFAULT_MULTICHANNEL_NUM = 6; static constexpr uint32_t DEFAULT_MULTICHANNEL_CHANNELLAYOUT = 1551; static constexpr float MAX_SINK_VOLUME_LEVEL = 1.0; static constexpr uint32_t DEFAULT_MULTICHANNEL_FRAME_LEN_MS = 20; +static constexpr uint32_t DEFAULT_FRAME_LEN_MS = 20; static constexpr uint32_t MS_PER_SECOND = 1000; static constexpr uint32_t BASE_TEN = 10; static constexpr uint32_t FRAME_LENGTH_LIMIT = 38400; @@ -540,6 +541,11 @@ void TransSinkInfoToNodeInfo(const HpaeSinkInfo &sinkInfo, const std::weak_ptrReset(); } mixerNode_->Reset(); @@ -70,33 +70,24 @@ bool HpaeSourceProcessCluster::ResetAll() std::shared_ptr HpaeSourceProcessCluster::GetSharedInstance() { - if (captureEffectNode_ == nullptr) { - return mixerNode_; - } - return captureEffectNode_; + return mixerNode_; } OutputPort *HpaeSourceProcessCluster::GetOutputPort() { - return captureEffectNode_ != nullptr ? captureEffectNode_->GetOutputPort() : mixerNode_->GetOutputPort(); + return mixerNode_->GetOutputPort(); } std::shared_ptr HpaeSourceProcessCluster::GetSharedInstance(HpaeNodeInfo &nodeInfo) { std::string sourceOutputNodeKey = TransNodeInfoToStringKey(nodeInfo); HpaeNodeInfo effectNodeInfo = mixerNode_->GetNodeInfo(); - if (captureEffectNode_ != nullptr) { - captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); - } std::string effectNodeKey = TransNodeInfoToStringKey(effectNodeInfo); - AUDIO_INFO_LOG("sourceOutput:[%{public}s] effectNode:[%{public}s]", + AUDIO_INFO_LOG("sourceOutput:[%{public}s] mixerNode:[%{public}s]", sourceOutputNodeKey.c_str(), effectNodeKey.c_str()); if (CheckHpaeNodeInfoIsSame(nodeInfo, effectNodeInfo)) { - AUDIO_INFO_LOG("Specification of sourceOutputNode is same with capture effect"); - if (captureEffectNode_ != nullptr) { - return captureEffectNode_; - } - return mixerNode; + AUDIO_INFO_LOG("Config of sourceOutputNode is same with capture mixerNode"); + return mixerNode_; } if (!SafeGetMap(fmtConverterNodeMap_, sourceOutputNodeKey)) { fmtConverterNodeMap_[sourceOutputNodeKey] = @@ -111,22 +102,19 @@ OutputPort *HpaeSourceProcessCluster::GetOutputPort(HpaeNodeInf { std::string sourceOutputNodeKey = TransNodeInfoToStringKey(nodeInfo); HpaeNodeInfo effectNodeInfo = mixerNode_->GetNodeInfo(); - if (captureEffectNode_ != nullptr) { - captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); - } std::string effectNodeKey = TransNodeInfoToStringKey(effectNodeInfo); - AUDIO_INFO_LOG("sourceOutput:[%{public}s] effectNode:[%{public}s]", + AUDIO_INFO_LOG("sourceOutput:[%{public}s] mixerNode:[%{public}s]", sourceOutputNodeKey.c_str(), effectNodeKey.c_str()); if (CheckHpaeNodeInfoIsSame(nodeInfo, effectNodeInfo)) { - AUDIO_INFO_LOG("Specification of sourceOutputNode is same with capture effect"); - return captureEffectNode_ != nullptr ? captureEffectNode_->GetOutputPort() : mixerNode_->GetOutputPort(); + AUDIO_INFO_LOG("Config of sourceOutputNode is same with capture mixerNode"); + return mixerNode_->GetOutputPort(); } CHECK_AND_RETURN_RET_LOG(SafeGetMap(fmtConverterNodeMap_, sourceOutputNodeKey), - captureEffectNode_->GetOutputPort(), + mixerNode_->GetOutputPort(), "not find the sourceOutputNodeKey = %{public}s", sourceOutputNodeKey.c_str()); if (isDisConnect && fmtConverterNodeMap_[sourceOutputNodeKey]->GetOutputPortNum() <= 1) { // disconnect fmtConverterNode->upEffectNode - AUDIO_INFO_LOG("disconnect fmtConverterNode between effectnode[[%{public}s] and sourceoutputnode[%{public}s]", + AUDIO_INFO_LOG("disconnect fmtConverterNode between mixerNode[[%{public}s] and sourceoutputnode[%{public}s]", effectNodeKey.c_str(), sourceOutputNodeKey.c_str()); fmtConverterNodeMap_[sourceOutputNodeKey]->DisConnect(mixerNode_); } @@ -136,15 +124,23 @@ OutputPort *HpaeSourceProcessCluster::GetOutputPort(HpaeNodeInf void HpaeSourceProcessCluster::Connect(const std::shared_ptr> &preNode) { HpaeNodeInfo effectNodeInfo; - captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); - captureEffectNode_->ConnectWithInfo(preNode, effectNodeInfo); + GetCapturerEffectConfig(effectNodeInfo); + if (captureEffectNode_ != nullptr) { + captureEffectNode_->ConnectWithInfo(preNode, effectNodeInfo); + } else { + mixerNode_->ConnectWithInfo(preNode, effectNodeInfo); + } } void HpaeSourceProcessCluster::DisConnect(const std::shared_ptr> &preNode) { HpaeNodeInfo effectNodeInfo; - captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); - captureEffectNode_->DisConnectWithInfo(preNode, effectNodeInfo); + GetCapturerEffectConfig(effectNodeInfo); + if (captureEffectNode_ != nullptr) { + captureEffectNode_->DisConnectWithInfo(preNode, effectNodeInfo); + } else { + mixerNode_->DisConnectWithInfo(preNode, effectNodeInfo); + } } void HpaeSourceProcessCluster::ConnectWithInfo(const std::shared_ptr>& preNode, @@ -211,15 +207,14 @@ bool HpaeSourceProcessCluster::GetCapturerEffectConfig(HpaeNodeInfo &nodeInfo, H size_t HpaeSourceProcessCluster::GetOutputPortNum() { - CHECK_AND_RETURN_RET(captureEffectNode_ != nullptr, mixerNode_->GetOutputPortNum()); - return captureEffectNode_->GetOutputPortNum(); + return mixerNode_->GetOutputPortNum(); } int32_t HpaeSourceProcessCluster::CaptureEffectCreate(uint64_t sceneKeyCode, CaptureEffectAttr attr) { CHECK_AND_RETURN_RET_LOG(captureEffectNode_, ERROR_ILLEGAL_STATE, "captureEffectNode_ is nullptr"); HpaeNodeInfo nodeInfo; - if (captureEffectNode_->CaptureEffectCreate(sceneKeyCode, attr) != 0 || GetCapturerEffectConfig(nodeInfo)) { + if (captureEffectNode_->CaptureEffectCreate(sceneKeyCode, attr) != 0 || !GetCapturerEffectConfig(nodeInfo)) { captureEffectNode_ = nullptr; return ERROR_ILLEGAL_STATE; } @@ -242,6 +237,11 @@ bool HpaeSourceProcessCluster::IsEffectNodeValid() } // for ut test +uint32_t HpaeSourceProcessCluster::GetMixerNodeUseCount() +{ + return mixerNode_.use_count(); +} + uint32_t HpaeSourceProcessCluster::GetCapturerEffectNodeUseCount() { return captureEffectNode_.use_count(); diff --git a/services/audio_engine/node/src/hpae_virtual_process_cluster.cpp b/services/audio_engine/node/src/hpae_virtual_process_cluster.cpp index dc316fe77f..bd2a8d2c31 100644 --- a/services/audio_engine/node/src/hpae_virtual_process_cluster.cpp +++ b/services/audio_engine/node/src/hpae_virtual_process_cluster.cpp @@ -29,7 +29,7 @@ namespace OHOS { namespace AudioStandard { namespace HPAE { -HpaeVirtualProcessCluster::HpaeVirtualProcessCluster(HpaeNodeInfo nodeInfo, HpaeSinkInfo &sinkInfo) +HpaeVirtualProcessCluster::HpaeVirtualProcessCluster(HpaeNodeInfo nodeInfo) : HpaeNode(nodeInfo), mixerNode_(std::make_shared(nodeInfo)) { #ifdef ENABLE_HIDUMP_DFX diff --git a/services/audio_engine/test/unittest/BUILD.gn b/services/audio_engine/test/unittest/BUILD.gn index 6cec754c06..37c2221106 100644 --- a/services/audio_engine/test/unittest/BUILD.gn +++ b/services/audio_engine/test/unittest/BUILD.gn @@ -232,6 +232,48 @@ ohos_unittest("hpae_sink_output_node_test") { resource_config_file = "./resource/ohos_test.xml" } +ohos_unittest("hpae_sink_virtual_output_node_test") { + module_out_path = module_output_path + sources = [ + "common/test_case_common.cpp", + "node/hpae_sink_virtual_output_node_test.cpp", + ] + + configs = [ ":audio_engine_private_config" ] + + deps = [ + "../../:audio_engine_manager", + "../../:audio_engine_node", + "../../:audio_engine_utils", + "../../../audio_service:audio_common", + ] + + external_deps = engine_test_external_deps + + resource_config_file = "./resource/ohos_test.xml" +} + +ohos_unittest("hpae_virtual_process_cluster_test") { + module_out_path = module_output_path + sources = [ + "common/test_case_common.cpp", + "node/hpae_virtual_process_cluster_test.cpp", + ] + + configs = [ ":audio_engine_private_config" ] + + deps = [ + "../../:audio_engine_manager", + "../../:audio_engine_node", + "../../:audio_engine_utils", + "../../../audio_service:audio_common", + ] + + external_deps = engine_test_external_deps + + resource_config_file = "./resource/ohos_test.xml" +} + ohos_unittest("hpae_source_process_cluster_test") { module_out_path = module_output_path sources = [ diff --git a/services/audio_engine/test/unittest/manager/hpae_capturer_manager_test.cpp b/services/audio_engine/test/unittest/manager/hpae_capturer_manager_test.cpp index f048ec7ffd..a5aaf84ca3 100644 --- a/services/audio_engine/test/unittest/manager/hpae_capturer_manager_test.cpp +++ b/services/audio_engine/test/unittest/manager/hpae_capturer_manager_test.cpp @@ -1066,6 +1066,47 @@ HWTEST_F(HpaeCapturerManagerTest, CreateStream_003, TestSize.Level1) EXPECT_EQ(capturerManager->IsInit(), true); EXPECT_EQ(capturerManager->CreateStream(streamInfo), ERROR); } + +/** + * @tc.name : Test AddRemoveCaptureInjectorTest + * @tc.type : FUNC + * @tc.number: AddRemoveCaptureInjectorTest + * @tc.desc : Test AddCapturerInjector and RemoveCapturerInjector func + */ +HWTEST_F(HpaeCapturerManagerTest, AddRemoveCaptureInjectorTest, TestSize.Level1) +{ + HpaeSourceInfo sourceInfo; + InitSourceInfo(sourceInfo); + std::shared_ptr capturerManager = std::make_shared(sourceInfo); + EXPECT_EQ(capturerManager->Init(), SUCCESS); + WaitForMsgProcessing(capturerManager); + HpaeStreamInfo streamInfo; + InitReloadStreamInfo(streamInfo); + streamInfo.sourceType = SOURCE_TYPE_MIC; + EXPECT_EQ(capturerManager->CreateStream(streamInfo) == SUCCESS, true); + WaitForMsgProcessing(capturerManager); + + HpaeProcessorType sceneType = TransSourceTypeToSceneType(streamInfo.sourceType); + auto it = capturerManager->sceneClusterMap_.find(sceneType); + ASSERT_EQ(it != capturerManager->sceneClusterMap_.end(), true); + auto sceneCluster = it->second; + ASSERT_EQ(sceneCluster != nullptr , true); + HpaeNodeInfo nodeInfo; + nodeInfo.deviceClass = sourceInfo.deviceClass; + nodeInfo.channels = sourceInfo.channels; + nodeInfo.format = sourceInfo.format; + nodeInfo.frameLen = sourceInfo.frameLen; + nodeInfo.samplingRate = sourceInfo.samplingRate; + nodeInfo.sourceBufferType = HPAE_SOURCE_BUFFER_TYPE_MIC; + nodeInfo.statusCallback = capturerManager; + std::shared_ptr preNode = std::make_shared(nodeInfo); + EXPECT_EQ(capturerManager->AddCaptureInjector(preNode, streamInfo.sourceType), SUCCESS); + WaitForMsgProcessing(capturerManager); + EXPECT_EQ(preNode.use_count(), 2); + EXPECT_EQ(capturerManager->RemoveCaptureInjector(preNode, streamInfo.sourceType), SUCCESS); + WaitForMsgProcessing(capturerManager); + EXPECT_EQ(preNode.use_count(), 1); +} } // namespace HPAE } // namespace AudioStandard } // namespace OHOS \ No newline at end of file diff --git a/services/audio_engine/test/unittest/manager/hpae_manager_test.cpp b/services/audio_engine/test/unittest/manager/hpae_manager_test.cpp index 851ed22dff..f9e5b9a03b 100644 --- a/services/audio_engine/test/unittest/manager/hpae_manager_test.cpp +++ b/services/audio_engine/test/unittest/manager/hpae_manager_test.cpp @@ -1807,8 +1807,7 @@ HWTEST_F(HpaeManagerUnitTest, InjectorToPrimaryCapturer, TestSize.Level1) EXPECT_EQ(hpaeManager_->IsInit(), true); std::shared_ptr callback = std::make_shared(); hpaeManager_->RegisterSerivceCallback(callback); - - AudioModuleInfo moduleInfo = GetSinkAudioModeInfo("virtual"); // todo : rewrite correct name + AudioModuleInfo moduleInfo = GetSinkAudioModeInfo("Virtual_Injector"); // todo : rewrite correct name EXPECT_EQ(hpaeManager_->OpenAudioPort(moduleInfo), SUCCESS); WaitForMsgProcessing(hpaeManager_); int32_t injectorPortId = callback->GetPortId(); @@ -1833,7 +1832,7 @@ HWTEST_F(HpaeManagerUnitTest, InjectorToPrimaryCapturer, TestSize.Level1) HpaeStreamInfo streamInfo2 = GetCaptureStreamInfo(); streamInfo2.deviceName = moduleInfo2.name; - streamInfo.sourceType = SOURCE_TYPE_MIC; + streamInfo2.sourceType = SOURCE_TYPE_MIC; hpaeManager_->CreateStream(streamInfo2); WaitForMsgProcessing(hpaeManager_); @@ -1841,9 +1840,10 @@ HWTEST_F(HpaeManagerUnitTest, InjectorToPrimaryCapturer, TestSize.Level1) hpaeManager_->Start(HPAE_STREAM_CLASS_TYPE_RECORD, streamInfo2.sessionId); hpaeManager_->Start(HPAE_STREAM_CLASS_TYPE_PLAY, streamInfo.sessionId); sleep(3); // 3s for sleep - hpaeManager_->Stop(HPAE_STREAM_CLASS_TYPE_RECORD, streamInfo2.sessionId); hpaeManager_->Stop(HPAE_STREAM_CLASS_TYPE_PLAY, streamInfo.sessionId); WaitForMsgProcessing(hpaeManager_); + hpaeManager_->Stop(HPAE_STREAM_CLASS_TYPE_RECORD, streamInfo2.sessionId); + WaitForMsgProcessing(hpaeManager_); hpaeManager_->RemoveCaptureInjector(injectorPortId, capturerPortId, streamInfo2.sourceType); WaitForMsgProcessing(hpaeManager_); hpaeManager_->CloseAudioPort(injectorPortId); @@ -1860,7 +1860,7 @@ HWTEST_F(HpaeManagerUnitTest, InjectorToEndPointCapturer, TestSize.Level1) std::shared_ptr callback = std::make_shared(); hpaeManager_->RegisterSerivceCallback(callback); - AudioModuleInfo moduleInfo = GetSinkAudioModeInfo("virtual"); // todo : rewrite correct name + AudioModuleInfo moduleInfo = GetSinkAudioModeInfo("Virtual_Injector"); // todo : rewrite correct name EXPECT_EQ(hpaeManager_->OpenAudioPort(moduleInfo), SUCCESS); WaitForMsgProcessing(hpaeManager_); int32_t injectorPortId = callback->GetPortId(); @@ -1868,7 +1868,7 @@ HWTEST_F(HpaeManagerUnitTest, InjectorToEndPointCapturer, TestSize.Level1) auto it = hpaeManager_->sinkVirtualOutputNodeMap_.find(injectorPortId); EXPECT_EQ(it != hpaeManager_->sinkVirtualOutputNodeMap_.end(), true); auto sinkOutputNode = it->second; - EXPECT_EQ(sinkOutputNode != nullptr, true); + ASSERT_EQ(sinkOutputNode != nullptr, true); HpaeNodeInfo nodeInfo = sinkOutputNode->GetNodeInfo(); EXPECT_EQ(moduleInfo.channels, std::to_string(nodeInfo.channels)); EXPECT_EQ(moduleInfo.rate, std::to_string(nodeInfo.samplingRate)); @@ -1895,4 +1895,42 @@ HWTEST_F(HpaeManagerUnitTest, InjectorToEndPointCapturer, TestSize.Level1) hpaeManager_->CloseAudioPort(injectorPortId); WaitForMsgProcessing(hpaeManager_); } + +HWTEST_F(HpaeManagerUnitTest, InjectorUpdataAudioPortInfoTest, TestSize.Level1) +{ + EXPECT_NE(hpaeManager_, nullptr); + hpaeManager_->Init(); + sleep(1); + EXPECT_EQ(hpaeManager_->IsInit(), true); + std::shared_ptr callback = std::make_shared(); + hpaeManager_->RegisterSerivceCallback(callback); + + AudioModuleInfo moduleInfo = GetSinkAudioModeInfo("Virtual_Injector"); // todo : rewrite correct name + EXPECT_EQ(hpaeManager_->OpenAudioPort(moduleInfo), SUCCESS); + WaitForMsgProcessing(hpaeManager_); + int32_t injectorPortId = callback->GetPortId(); + + auto it = hpaeManager_->sinkVirtualOutputNodeMap_.find(injectorPortId); + EXPECT_EQ(it != hpaeManager_->sinkVirtualOutputNodeMap_.end(), true); + auto sinkOutputNode = it->second; + ASSERT_EQ(sinkOutputNode != nullptr, true); + HpaeNodeInfo &nodeInfo = sinkOutputNode->GetNodeInfo(); + EXPECT_EQ(moduleInfo.channels, std::to_string(nodeInfo.channels)); + EXPECT_EQ(moduleInfo.rate, std::to_string(nodeInfo.samplingRate)); + + moduleInfo.channels = "4"; + moduleInfo.rate = "16000"; + hpaeManager_->UpdateAudioPortInfo(injectorPortId, moduleInfo); + WaitForMsgProcessing(hpaeManager_); + EXPECT_EQ(moduleInfo.channels, std::to_string(nodeInfo.channels)); + EXPECT_EQ(moduleInfo.rate, std::to_string(nodeInfo.samplingRate)); + + moduleInfo.channels = "0"; + hpaeManager_->UpdateAudioPortInfo(injectorPortId, moduleInfo); + WaitForMsgProcessing(hpaeManager_); + EXPECT_NE(moduleInfo.channels, std::to_string(nodeInfo.channels)); + + hpaeManager_->CloseAudioPort(injectorPortId); + WaitForMsgProcessing(hpaeManager_); +} } // namespace \ No newline at end of file diff --git a/services/audio_engine/test/unittest/manager/hpae_render_manager_test.cpp b/services/audio_engine/test/unittest/manager/hpae_render_manager_test.cpp index 33a716a332..1df532b608 100644 --- a/services/audio_engine/test/unittest/manager/hpae_render_manager_test.cpp +++ b/services/audio_engine/test/unittest/manager/hpae_render_manager_test.cpp @@ -19,10 +19,13 @@ #include "audio_errors.h" #include "hpae_renderer_manager.h" #include "hpae_offload_renderer_manager.h" +#include "hpae_injector_renderer_manager.h" #include "hpae_output_cluster.h" #include "hpae_co_buffer_node.h" #include "hpae_inner_capturer_manager.h" #include "audio_effect_chain_manager.h" +#include "hpae_sink_virtual_output_node.h" +#include "hpae_node_common.h" #include "hpae_mocks.h" #include #include @@ -85,6 +88,16 @@ static void WaitForMsgProcessing(std::shared_ptr &hpaeRendere EXPECT_EQ(waitCount < waitCountThd, true); } +static std::shared_ptr SetSinkVirtualOutputNode(const HpaeSinkInfo &sinkInfo, + const std::shared_ptr &rendererManager) +{ + HpaeNodeInfo nodeInfo; + TransSinkInfoToNodeInfo(sinkInfo, rendererManager, nodeInfo); + std::shared_ptr sinkOutputNode = std::make_shared(nodeInfo); + rendererManager->SetSinkVirtualOutputNode(sinkOutputNode); + return sinkOutputNode; +} + template void TestIRendererManagerConstruct() { @@ -99,6 +112,7 @@ void TestIRendererManagerConstruct() sinkInfo.channels = STEREO; sinkInfo.deviceType = DEVICE_TYPE_SPEAKER; std::shared_ptr hpaeRendererManager = std::make_shared(sinkInfo); + SetSinkVirtualOutputNode(sinkInfo, hpaeRendererManager); HpaeSinkInfo dstSinkInfo = hpaeRendererManager->GetSinkInfo(); EXPECT_EQ(dstSinkInfo.deviceNetId == sinkInfo.deviceNetId, true); EXPECT_EQ(dstSinkInfo.deviceClass == sinkInfo.deviceClass, true); @@ -124,6 +138,7 @@ void TestIRendererManagerInit() sinkInfo.channels = STEREO; sinkInfo.deviceType = DEVICE_TYPE_SPEAKER; std::shared_ptr hpaeRendererManager = std::make_shared(sinkInfo); + SetSinkVirtualOutputNode(sinkInfo, hpaeRendererManager); EXPECT_EQ(hpaeRendererManager->Init() == SUCCESS, true); WaitForMsgProcessing(hpaeRendererManager); EXPECT_EQ(hpaeRendererManager->IsInit(), true); @@ -168,6 +183,7 @@ void TestRenderManagerReload() sinkInfo.channels = STEREO; sinkInfo.deviceType = DEVICE_TYPE_SPEAKER; std::shared_ptr hpaeRendererManager = std::make_shared(sinkInfo); + SetSinkVirtualOutputNode(sinkInfo, hpaeRendererManager); EXPECT_EQ(hpaeRendererManager->Init() == SUCCESS, true); WaitForMsgProcessing(hpaeRendererManager); EXPECT_EQ(hpaeRendererManager->IsInit(), true); @@ -211,6 +227,7 @@ void TestIRendererManagerCreateDestoryStream() sinkInfo.channels = STEREO; sinkInfo.deviceType = DEVICE_TYPE_SPEAKER; std::shared_ptr hpaeRendererManager = std::make_shared(sinkInfo); + SetSinkVirtualOutputNode(sinkInfo, hpaeRendererManager); EXPECT_EQ(hpaeRendererManager->Init() == SUCCESS, true); WaitForMsgProcessing(hpaeRendererManager); EXPECT_EQ(hpaeRendererManager->IsInit(), true); @@ -347,6 +364,8 @@ HWTEST_F(HpaeRendererManagerTest, constructHpaeRendererManagerTest, TestSize.Lev TestIRendererManagerConstruct(); std::cout << "test offload" << std::endl; TestIRendererManagerConstruct(); + std::cout << "test injector" << std::endl; + TestIRendererManagerConstruct(); } HWTEST_F(HpaeRendererManagerTest, HpaeRendererManagerInitTest, TestSize.Level1) @@ -354,6 +373,8 @@ HWTEST_F(HpaeRendererManagerTest, HpaeRendererManagerInitTest, TestSize.Level1) TestIRendererManagerInit(); std::cout << "test offload" << std::endl; TestIRendererManagerInit(); + std::cout << "test injector" << std::endl; + TestIRendererManagerInit(); } HWTEST_F(HpaeRendererManagerTest, HpaeRendererManagerReloadTest, TestSize.Level1) @@ -361,6 +382,8 @@ HWTEST_F(HpaeRendererManagerTest, HpaeRendererManagerReloadTest, TestSize.Level1 TestRenderManagerReload(); std::cout << "test offload" << std::endl; TestRenderManagerReload(); + std::cout << "test injector" << std::endl; + TestRenderManagerReload(); } HWTEST_F(HpaeRendererManagerTest, HpaeRendererManagerCreateDestoryStreamTest, TestSize.Level1) @@ -368,6 +391,8 @@ HWTEST_F(HpaeRendererManagerTest, HpaeRendererManagerCreateDestoryStreamTest, Te TestIRendererManagerCreateDestoryStream(); std::cout << "test offload" << std::endl; TestIRendererManagerCreateDestoryStream(); + std::cout << "test injector" << std::endl; + TestIRendererManagerCreateDestoryStream(); } HWTEST_F(HpaeRendererManagerTest, HpaeRendererManagerStartPuaseStreamTest, TestSize.Level1) @@ -1842,4 +1867,177 @@ HWTEST_F(HpaeRendererManagerTest, HpaeRendererManagerCreateStream_002, TestSize. streamInfo.frameLen = OVERSIZED_FRAME_LENGTH; EXPECT_EQ(hpaeRendererManager->CreateStream(streamInfo), ERROR); } + +static HpaeSinkInfo GetSinkInfo() +{ + HpaeSinkInfo sinkInfo; + sinkInfo.deviceNetId = DEFAULT_TEST_DEVICE_NETWORKID; + sinkInfo.deviceClass = DEFAULT_TEST_DEVICE_CLASS; + sinkInfo.adapterName = DEFAULT_TEST_DEVICE_CLASS; + sinkInfo.filePath = g_rootPath + "constructHpaeRendererManagerTest.pcm"; + sinkInfo.frameLen = FRAME_LENGTH_960; + sinkInfo.samplingRate = SAMPLE_RATE_48000; + sinkInfo.format = SAMPLE_F32LE; + sinkInfo.channels = STEREO; + sinkInfo.deviceType = DEVICE_TYPE_SPEAKER; + return sinkInfo; +} + +/** + * @tc.name : Test HpaeInjectorRendererManagerStartPauseTest_001 + * @tc.type : FUNC + * @tc.number: HpaeInjectorRendererManagerStartPauseTest_001 + * @tc.desc : Test HpaeInjectorRendererManager start pause stop with + */ +HWTEST_F(HpaeRendererManagerTest, HpaeInjectorRendererManagerStartPauseTest_001, TestSize.Level1) +{ + HpaeSinkInfo sinkInfo = GetSinkInfo(); + auto hpaeRendererManager = std::make_shared(sinkInfo); + auto sinkOutputNode = SetSinkVirtualOutputNode(sinkInfo, hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->Init() == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->IsInit(), true); + HpaeStreamInfo streamInfo; + TestRendererManagerCreateStream(hpaeRendererManager, streamInfo); + HpaeSinkInputInfo sinkInputInfo; + std::shared_ptr writeIncDataCb = std::make_shared(SAMPLE_S16LE); + EXPECT_EQ(hpaeRendererManager->RegisterWriteCallback(streamInfo.sessionId, writeIncDataCb), SUCCESS); + EXPECT_EQ(writeIncDataCb.use_count() == 1, true); + EXPECT_EQ(hpaeRendererManager->Start(streamInfo.sessionId) == SUCCESS, true); + + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->GetSinkInputInfo(streamInfo.sessionId, sinkInputInfo) == SUCCESS, true); + EXPECT_EQ(sinkInputInfo.rendererSessionInfo.state, HPAE_SESSION_RUNNING); + EXPECT_EQ(hpaeRendererManager->CheckIsStreamRunning(), true); + EXPECT_EQ(hpaeRendererManager->IsRunning(), false); + EXPECT_EQ(sinkOutputNode->GetIsReadFinished(), false); + EXPECT_EQ(hpaeRendererManager->Pause(streamInfo.sessionId) == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->GetSinkInputInfo(streamInfo.sessionId, sinkInputInfo) == SUCCESS, true); + EXPECT_EQ(sinkInputInfo.rendererSessionInfo.state, HPAE_SESSION_PAUSING); + EXPECT_EQ(hpaeRendererManager->Start(streamInfo.sessionId) == SUCCESS, true); + + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->GetSinkInputInfo(streamInfo.sessionId, sinkInputInfo) == SUCCESS, true); + EXPECT_EQ(sinkInputInfo.rendererSessionInfo.state, HPAE_SESSION_RUNNING); + EXPECT_EQ(hpaeRendererManager->IsRunning(), false); + EXPECT_EQ(sinkOutputNode->GetIsReadFinished(), false); + EXPECT_EQ(hpaeRendererManager->Stop(streamInfo.sessionId) == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + auto it = hpaeRendererManager->sinkInputNodeMap_.find(streamInfo.sessionId); + ASSERT_EQ(it != hpaeRendererManager->sinkInputNodeMap_.end(), true); + auto sinkInputNode = it->second; + ASSERT_EQ(sinkInputNode != nullptr, true); + hpaeRendererManager->TriggerStreamState(streamInfo.sessionId, sinkInputNode); + + EXPECT_EQ(hpaeRendererManager->Drain(streamInfo.sessionId) == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->Flush(streamInfo.sessionId) == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->GetSinkInputInfo(streamInfo.sessionId, sinkInputInfo) == SUCCESS, true); + EXPECT_EQ(sinkInputInfo.rendererSessionInfo.state, HPAE_SESSION_STOPPED); + EXPECT_EQ(hpaeRendererManager->Release(streamInfo.sessionId) == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ( + hpaeRendererManager->GetSinkInputInfo(streamInfo.sessionId, sinkInputInfo) == ERR_INVALID_OPERATION, true); + EXPECT_EQ(hpaeRendererManager->DeInit() == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); +} + +/** + * @tc.name : Test HpaeInjectorRendererManagerTest + * @tc.type : FUNC + * @tc.number: HpaeInjectorRendererManagerTest + * @tc.desc : Test HpaeInjectorRendererManager invalid state and func + */ +HWTEST_F(HpaeRendererManagerTest, HpaeInjectorRendererManagerTest, TestSize.Level1) +{ + HpaeSinkInfo sinkInfo = GetSinkInfo(); + auto hpaeRendererManager = std::make_shared(sinkInfo); + auto sinkOutputNode = SetSinkVirtualOutputNode(sinkInfo, hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->SetMute(false), SUCCESS); + HpaeStreamInfo streamInfo; + streamInfo.channels = STEREO; + streamInfo.samplingRate = SAMPLE_RATE_44100; + streamInfo.format = SAMPLE_S16LE; + streamInfo.frameLen = FRAME_LENGTH_882; + streamInfo.sessionId = TEST_STREAM_SESSION_ID; + streamInfo.streamType = STREAM_MUSIC; + streamInfo.streamClassType = HPAE_STREAM_CLASS_TYPE_PLAY; + EXPECT_EQ(hpaeRendererManager->CreateStream(streamInfo) == SUCCESS, false); + WaitForMsgProcessing(hpaeRendererManager); + hpaeRendererManager->OnNodeStatusUpdate(streamInfo.sessionId, OPERATION_STOPPED); + EXPECT_NE(hpaeRendererManager->DestroyStream(streamInfo.sessionId) == SUCCESS, true); + EXPECT_EQ(hpaeRendererManager->DeactivateThread(), true); + EXPECT_EQ(hpaeRendererManager->SetClientVolume(streamInfo.sessionId, 0.f), SUCCESS); + EXPECT_EQ(hpaeRendererManager->SetRate(streamInfo.sessionId, 0), SUCCESS); + EXPECT_EQ(hpaeRendererManager->SetAudioEffectMode(streamInfo.sessionId, 0), SUCCESS); + int32_t mode = 0; + EXPECT_EQ(hpaeRendererManager->GetAudioEffectMode(streamInfo.sessionId, mode), SUCCESS); + EXPECT_EQ(hpaeRendererManager->SetPrivacyType(streamInfo.sessionId, 0), SUCCESS); + int32_t type = 0; + EXPECT_EQ(hpaeRendererManager->GetPrivacyType(streamInfo.sessionId, type), SUCCESS); + std::shared_ptr callback = nullptr; + EXPECT_EQ(hpaeRendererManager->RegisterReadCallback(streamInfo.sessionId, callback), SUCCESS); + EXPECT_EQ(hpaeRendererManager->GetWritableSize(streamInfo.sessionId), 0); + EXPECT_EQ(hpaeRendererManager->UpdateSpatializationState(streamInfo.sessionId, false, false), SUCCESS); + EXPECT_EQ(hpaeRendererManager->UpdateMaxLength(streamInfo.sessionId, 0), SUCCESS); + std::vector vct = hpaeRendererManager->GetAllSinkInputsInfo(); + EXPECT_EQ(vct.size(), 0); + EXPECT_EQ(hpaeRendererManager->RefreshProcessClusterByDevice(), SUCCESS); + EXPECT_EQ(hpaeRendererManager->DumpSinkInfo(), SUCCESS); + EXPECT_EQ(hpaeRendererManager->GetDeviceHDFDumpInfo() == "", true); + EXPECT_EQ(hpaeRendererManager->SetLoudnessGain(streamInfo.sessionId, 0.f), SUCCESS); + + EXPECT_EQ(hpaeRendererManager->Init() == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->IsInit(), true); + + EXPECT_EQ(hpaeRendererManager->DeactivateThread(), true); + hpaeRendererManager = nullptr; +} + +/** + * @tc.name : Test HpaeInjectorRendererManagerReloadTest + * @tc.type : FUNC + * @tc.number: HpaeInjectorRendererManagerReloadTest + * @tc.desc : Test HpaeInjectorRendererManager Reload + */ +HWTEST_F(HpaeRendererManagerTest, HpaeInjectorRendererManagerReloadTest, TestSize.Level1) +{ + HpaeSinkInfo sinkInfo = GetSinkInfo(); + auto hpaeRendererManager = std::make_shared(sinkInfo); + EXPECT_NE(hpaeRendererManager->ReloadRenderManager(sinkInfo) == SUCCESS, true); + EXPECT_EQ(hpaeRendererManager->IsInit(), false); + + auto sinkOutputNode = SetSinkVirtualOutputNode(sinkInfo, hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->ReloadRenderManager(sinkInfo), SUCCESS); + WaitForMsgProcessing(hpaeRendererManager); + EXPECT_EQ(hpaeRendererManager->IsInit(), true); + + HpaeStreamInfo streamInfo; + streamInfo.channels = STEREO; + streamInfo.samplingRate = SAMPLE_RATE_44100; + streamInfo.format = SAMPLE_S16LE; + streamInfo.frameLen = FRAME_LENGTH_882; + streamInfo.sessionId = TEST_STREAM_SESSION_ID; + streamInfo.streamType = STREAM_MUSIC; + streamInfo.streamClassType = HPAE_STREAM_CLASS_TYPE_PLAY; + + EXPECT_EQ(hpaeRendererManager->CreateStream(streamInfo) == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + hpaeRendererManager->Start(streamInfo.sessionId); + WaitForMsgProcessing(hpaeRendererManager); + + streamInfo.sessionId += 1; + EXPECT_EQ(hpaeRendererManager->CreateStream(streamInfo) == SUCCESS, true); + WaitForMsgProcessing(hpaeRendererManager); + hpaeRendererManager->Start(streamInfo.sessionId); + WaitForMsgProcessing(hpaeRendererManager); + + hpaeRendererManager->Stop(streamInfo.sessionId); + WaitForMsgProcessing(hpaeRendererManager); + + EXPECT_EQ(hpaeRendererManager->ReloadRenderManager(sinkInfo), SUCCESS); +} } // namespace \ No newline at end of file diff --git a/services/audio_engine/test/unittest/node/hpae_mixer_node_test.cpp b/services/audio_engine/test/unittest/node/hpae_mixer_node_test.cpp index 5f4d7c5c78..de8568fa8d 100644 --- a/services/audio_engine/test/unittest/node/hpae_mixer_node_test.cpp +++ b/services/audio_engine/test/unittest/node/hpae_mixer_node_test.cpp @@ -18,6 +18,7 @@ #include "hpae_sink_input_node.h" #include "hpae_mixer_node.h" #include "hpae_sink_output_node.h" +#include "hpae_source_input_cluster.h" #include "test_case_common.h" #include "audio_errors.h" @@ -122,4 +123,21 @@ HWTEST_F(HpaeMixerNodeTest, testHpaePlayOutConnectNode, TestSize.Level0) EXPECT_EQ(hpaeMixerNode->GetPreOutNum(), 0); } +HWTEST_F(HpaeMixerNodeTest, testMixerConnectWithInfo, TestSize.Level1) +{ + HpaeNodeInfo nodeInfo; + nodeInfo.nodeId = TEST_ID; + nodeInfo.frameLen = TEST_FRAMELEN; + nodeInfo.samplingRate = SAMPLE_RATE_48000; + nodeInfo.channels = STEREO; + nodeInfo.format = SAMPLE_F32LE; + std::shared_ptr hpaeMixerNode = std::make_shared(nodeInfo); + nodeInfo.channels = MONO; + std::shared_ptr cluster = std::make_shared(nodeInfo); + EXPECT_EQ(cluster->fmtConverterNodeMap_.size() == 0, true); + hpaeMixerNode->ConnectWithInfo(cluster, hpaeMixerNode->GetNodeInfo()); + EXPECT_EQ(cluster->fmtConverterNodeMap_.size() == 1, true); + hpaeMixerNode->DisConnectWithInfo(cluster, hpaeMixerNode->GetNodeInfo()); + EXPECT_EQ(cluster->fmtConverterNodeMap_.size() == 1, true); // not delete convertnode, equal 1 +} } // namespace \ No newline at end of file diff --git a/services/audio_engine/test/unittest/node/hpae_sink_virtual_output_node_test.cpp b/services/audio_engine/test/unittest/node/hpae_sink_virtual_output_node_test.cpp new file mode 100644 index 0000000000..460a409d04 --- /dev/null +++ b/services/audio_engine/test/unittest/node/hpae_sink_virtual_output_node_test.cpp @@ -0,0 +1,257 @@ +/* + * 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 +#include +#include +#include "hpae_sink_input_node.h" +#include "hpae_sink_virtual_output_node.h" +#include "test_case_common.h" +#include "audio_errors.h" + +using namespace testing::ext; +using namespace testing; + +namespace OHOS { +namespace AudioStandard { +namespace HPAE { +static constexpr uint32_t DEFAULT_RING_BUFFER_NUM = 1; +static constexpr uint32_t DEFAULT_FRAME_LEN_MS = 20; +static constexpr uint32_t MS_PER_SECOND = 1000; + +class HpaeSinkVirtualOutputNodeTest : public testing::Test { +protected: + void SetUp() override { + nodeInfo_.nodeId = 1; + nodeInfo_.samplingRate = SAMPLE_RATE_48000; + nodeInfo_.frameLen = 960; // 20ms at 48kHz + nodeInfo_.channels = STEREO; + nodeInfo_.format = SAMPLE_F32LE; + nodeInfo_.sessionId = 1001; // 1001 for sessionid + nodeInfo_.statusCallback.reset(); + } + + void TearDown() override {} + + HpaeNodeInfo nodeInfo_; +}; + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, ConstructHpaeSinkVirtualOutputNode, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + ASSERT_NE(node, nullptr); + EXPECT_EQ(node->GetSampleRate(), nodeInfo_.samplingRate); + EXPECT_EQ(node->GetFrameLen(), nodeInfo_.frameLen); + EXPECT_EQ(node->GetChannelCount(), nodeInfo_.channels); + EXPECT_EQ(node->GetBitWidth(), nodeInfo_.format); + EXPECT_EQ(node->GetSessionId(), nodeInfo_.sessionId); + EXPECT_EQ(node->ringCache_ != nullptr, true); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, PeekAudioDataInvalidBufferSize, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + uint8_t* buffer = nullptr; + size_t invalidSize = nodeInfo_.frameLen * nodeInfo_.channels * GetSizeFromFormat(nodeInfo_.format) - 1; + AudioStreamInfo audioStreamInfo; + + int32_t result = node->PeekAudioData(&buffer, invalidSize, audioStreamInfo); + EXPECT_EQ(result, ERROR_INVALID_PARAM); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, PeekAudioDataSuccess, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + uint8_t* buffer = nullptr; + size_t validSize = nodeInfo_.frameLen * nodeInfo_.channels * GetSizeFromFormat(nodeInfo_.format); + AudioStreamInfo audioStreamInfo; + + int32_t result = node->PeekAudioData(&buffer, validSize, audioStreamInfo); + EXPECT_EQ(result, SUCCESS); + EXPECT_NE(buffer, nullptr); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, ResetNode, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + std::shared_ptr inputNode = std::make_shared(nodeInfo_); + node->Connect(inputNode); + bool result = node->Reset(); + EXPECT_TRUE(result); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, ResetAllNodes, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + bool result = node->ResetAll(); + EXPECT_TRUE(result); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, GetSharedInstance, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + std::shared_ptr sharedInstance = node->GetSharedInstance(); + EXPECT_EQ(sharedInstance, node); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, GetOutputPort, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + OutputPort* port = node->GetOutputPort(); + EXPECT_NE(port, nullptr); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, RenderSinkInitNullRingCache, TestSize.Level1) +{ + HpaeNodeInfo info = nodeInfo_; + std::shared_ptr node = + std::make_shared(info); + node->ringCache_.reset(); + EXPECT_NE(node->RenderSinkInit(), SUCCESS); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, RenderSinkInitSuccess, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + int32_t result = node->RenderSinkInit(); + EXPECT_EQ(result, SUCCESS); + EXPECT_EQ(node->GetState(), STREAM_MANAGER_IDLE); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, RenderSinkDeInit, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + int32_t result = node->RenderSinkDeInit(); + EXPECT_EQ(result, SUCCESS); + EXPECT_EQ(node->GetState(), STREAM_MANAGER_RELEASED); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, RenderSinkStart, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + int32_t result = node->RenderSinkStart(); + EXPECT_EQ(result, SUCCESS); + EXPECT_EQ(node->GetState(), STREAM_MANAGER_RUNNING); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, RenderSinkStop, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + int32_t result = node->RenderSinkStop(); + EXPECT_EQ(result, SUCCESS); + EXPECT_EQ(node->GetState(), STREAM_MANAGER_SUSPENDED); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, GetPreOutNum, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + size_t num = node->GetPreOutNum(); + EXPECT_GE(num, 0); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, SetSinkState, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + int32_t result = node->SetSinkState(STREAM_MANAGER_RUNNING); + EXPECT_EQ(result, SUCCESS); + EXPECT_EQ(node->GetState(), STREAM_MANAGER_RUNNING); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, GetLatency, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + uint32_t latency = node->GetLatency(); + EXPECT_EQ(latency, 0); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, GetIsReadFinished, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + EXPECT_EQ(node->GetIsReadFinished(), true); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, ReloadNode, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + HpaeNodeInfo newInfo = nodeInfo_; + newInfo.samplingRate = SAMPLE_RATE_44100; + newInfo.frameLen = 882; // 20ms at 44.1kHz + newInfo.channels = MONO; + newInfo.format = SAMPLE_S16LE; + + int32_t result = node->ReloadNode(newInfo); + EXPECT_EQ(result, SUCCESS); + + EXPECT_EQ(node->GetSampleRate(), newInfo.samplingRate); + EXPECT_EQ(node->GetFrameLen(), newInfo.frameLen); + EXPECT_EQ(node->GetChannelCount(), newInfo.channels); + EXPECT_EQ(node->GetBitWidth(), newInfo.format); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, GetRingCacheSize, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + + size_t expectedSize = nodeInfo_.channels * + static_cast(GetSizeFromFormat(nodeInfo_.format)) * + nodeInfo_.samplingRate * DEFAULT_FRAME_LEN_MS / MS_PER_SECOND * + DEFAULT_RING_BUFFER_NUM; + + size_t actualSize = node->GetRingCacheSize(); + EXPECT_EQ(actualSize, expectedSize); +} + +HWTEST_F(HpaeSinkVirtualOutputNodeTest, HpaeSinkVirtualOutputNodeTestReload, TestSize.Level1) +{ + std::shared_ptr node = + std::make_shared(nodeInfo_); + node->ringCache_ = nullptr; + EXPECT_EQ(node->ringCache_ == nullptr, true); + node->ReloadNode(nodeInfo_); + EXPECT_EQ(node->ringCache_ != nullptr, true); +} +} // namespace HPAE +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/audio_engine/test/unittest/node/hpae_source_process_cluster_test.cpp b/services/audio_engine/test/unittest/node/hpae_source_process_cluster_test.cpp index 15f1f92389..224f23cbce 100644 --- a/services/audio_engine/test/unittest/node/hpae_source_process_cluster_test.cpp +++ b/services/audio_engine/test/unittest/node/hpae_source_process_cluster_test.cpp @@ -16,11 +16,13 @@ #include #include #include +#include "gmock/gmock.h" #include "hpae_source_process_cluster.h" #include "test_case_common.h" #include "audio_errors.h" #include "hpae_source_output_node.h" #include "hpae_source_input_cluster.h" +#include "hpae_source_input_node.h" using namespace testing::ext; using namespace testing; @@ -38,6 +40,13 @@ public: void TearDown(); }; +class MockHpaeCaptureEffectNode : public HpaeCaptureEffectNode { +public: + MockHpaeCaptureEffectNode(HpaeNodeInfo &nodeInfo) : HpaeCaptureEffectNode(nodeInfo) {} + MOCK_METHOD(int32_t, CaptureEffectCreate, (uint64_t sceneKeyCode, CaptureEffectAttr attr), (override)); + MOCK_METHOD(bool, GetCapturerEffectConfig, (HpaeNodeInfo & nodeInfo, HpaeSourceBufferType type), (override)); +}; + void HpaeSourceProcessClusterTest::SetUp() {} @@ -60,21 +69,21 @@ HWTEST_F(HpaeSourceProcessClusterTest, constructHpaeSourceProcessClusterNode, Te EXPECT_EQ(hpaeSourceProcessCluster->GetFrameLen(), nodeInfo.frameLen); EXPECT_EQ(hpaeSourceProcessCluster->GetChannelCount(), nodeInfo.channels); EXPECT_EQ(hpaeSourceProcessCluster->GetBitWidth(), nodeInfo.format); - EXPECT_EQ(hpaeSourceProcessCluster->GetCapturerEffectNodeUseCount(), 1); + EXPECT_EQ(hpaeSourceProcessCluster->GetMixerNodeUseCount(), 1); std::shared_ptr hpaeSourceOutputNode1 = std::make_shared(nodeInfo); hpaeSourceOutputNode1->ConnectWithInfo(hpaeSourceProcessCluster, nodeInfo); - EXPECT_EQ(hpaeSourceProcessCluster->GetCapturerEffectNodeUseCount(), 1 + 1); - EXPECT_EQ(hpaeSourceProcessCluster->GetConverterNodeCount(), 1); + EXPECT_EQ(hpaeSourceProcessCluster->GetMixerNodeUseCount(), 1 + 1); + EXPECT_EQ(hpaeSourceProcessCluster->GetConverterNodeCount(), 0); nodeInfo.samplingRate = SAMPLE_RATE_16000; std::shared_ptr hpaeSourceOutputNode2 = std::make_shared(nodeInfo); hpaeSourceOutputNode2->ConnectWithInfo(hpaeSourceProcessCluster, nodeInfo); - EXPECT_EQ(hpaeSourceProcessCluster->GetCapturerEffectNodeUseCount(), 1 + 1 + 1); - EXPECT_EQ(hpaeSourceProcessCluster->GetConverterNodeCount(), 1 + 1); + EXPECT_EQ(hpaeSourceProcessCluster->GetMixerNodeUseCount(), 1 + 1 + 1); + EXPECT_EQ(hpaeSourceProcessCluster->GetConverterNodeCount(), 1); hpaeSourceOutputNode2->DisConnectWithInfo(hpaeSourceProcessCluster, nodeInfo); - EXPECT_EQ(hpaeSourceProcessCluster->GetCapturerEffectNodeUseCount(), 1 + 1); + EXPECT_EQ(hpaeSourceProcessCluster->GetMixerNodeUseCount(), 1 + 1); HpaeNodeInfo sourceInputNodeInfo; sourceInputNodeInfo.frameLen = DEFAULT_FRAME_LENGTH; @@ -115,12 +124,85 @@ HWTEST_F(HpaeSourceProcessClusterTest, testInterfaces, TestSize.Level0) hpaeSourceProcessCluster->DoProcess(); uint64_t sceneKeyCode = INVALID_SCENE_KEY_CODE; CaptureEffectAttr attr; - EXPECT_NE(hpaeSourceProcessCluster->CaptureEffectCreate(sceneKeyCode, attr), 0); EXPECT_EQ(hpaeSourceProcessCluster->CaptureEffectRelease(sceneKeyCode), 0); + EXPECT_NE(hpaeSourceProcessCluster->CaptureEffectCreate(sceneKeyCode, attr), 0); + EXPECT_NE(hpaeSourceProcessCluster->CaptureEffectRelease(sceneKeyCode), 0); hpaeSourceProcessCluster->Connect(inputNode); hpaeSourceProcessCluster->DisConnect(inputNode); EXPECT_EQ(hpaeSourceProcessCluster->ResetAll(), true); } + +HWTEST_F(HpaeSourceProcessClusterTest, EffectNodeNotNullTest, TestSize.Level1) +{ + std::shared_ptr testStatuscallback = std::make_shared(); + HpaeNodeInfo nodeInfo; + nodeInfo.frameLen = DEFAULT_FRAME_LENGTH; + nodeInfo.samplingRate = SAMPLE_RATE_48000; + nodeInfo.channels = STEREO; + nodeInfo.format = SAMPLE_F32LE; + nodeInfo.sceneType = HPAE_SCENE_VOIP_UP; + nodeInfo.statusCallback = testStatuscallback; + std::shared_ptr hpaeSourceProcessCluster = + std::make_shared(nodeInfo); + std::shared_ptr inputNode = std::make_shared(nodeInfo); + hpaeSourceProcessCluster->Connect(inputNode); + EXPECT_EQ(inputNode.use_count(), 2); + hpaeSourceProcessCluster->DisConnect(inputNode); + EXPECT_EQ(inputNode.use_count(), 1); +} + +HWTEST_F(HpaeSourceProcessClusterTest, HpaeSourceProcessClusterCreateEffectTest, TestSize.Level1) +{ + std::shared_ptr testStatuscallback = std::make_shared(); + HpaeNodeInfo nodeInfo; + nodeInfo.frameLen = DEFAULT_FRAME_LENGTH; + nodeInfo.samplingRate = SAMPLE_RATE_48000; + nodeInfo.channels = STEREO; + nodeInfo.format = SAMPLE_F32LE; + nodeInfo.sceneType = HPAE_SCENE_VOIP_UP; + nodeInfo.statusCallback = testStatuscallback; + std::shared_ptr hpaeSourceProcessCluster = + std::make_shared(nodeInfo); + std::shared_ptr effectNode = + std::make_shared>(nodeInfo); + hpaeSourceProcessCluster->captureEffectNode_ = effectNode; + CaptureEffectAttr testAttr; + EXPECT_CALL(*effectNode, CaptureEffectCreate(_, _)) + .WillOnce([]() { return SUCCESS; }); // Success + + // Mock GetCapturerEffectConfig to succeed and modify nodeInfo + HpaeNodeInfo modifiedNodeInfo = nodeInfo; + modifiedNodeInfo.frameLen = 1024; // Modified value + EXPECT_CALL(*effectNode, GetCapturerEffectConfig(_, _)) + .WillOnce([]() { return true; }); // Success with modified nodeInfo + + auto result = hpaeSourceProcessCluster->CaptureEffectCreate(12345, testAttr); + + EXPECT_EQ(result, 0); // Success + EXPECT_NE(hpaeSourceProcessCluster->mixerNode_, nullptr); // Mixer node should be created + EXPECT_EQ(hpaeSourceProcessCluster->captureEffectNode_, effectNode); // Should not be reset +} + +HWTEST_F(HpaeSourceProcessClusterTest, HpaeSourceProcessClusterInjectTest, TestSize.Level1) +{ + std::shared_ptr testStatuscallback = std::make_shared(); + HpaeNodeInfo nodeInfo; + nodeInfo.frameLen = DEFAULT_FRAME_LENGTH; + nodeInfo.samplingRate = SAMPLE_RATE_48000; + nodeInfo.channels = STEREO; + nodeInfo.format = SAMPLE_F32LE; + nodeInfo.sceneType = HPAE_SCENE_VOIP_UP; + nodeInfo.statusCallback = testStatuscallback; + std::shared_ptr hpaeSourceProcessCluster = + std::make_shared(nodeInfo); + + nodeInfo.channels = MONO; + std::shared_ptr inputNode = std::make_shared(nodeInfo); + hpaeSourceProcessCluster->ConnectInjector(inputNode); + EXPECT_EQ(hpaeSourceProcessCluster->injectorFmtConverterNodeMap_.size() == 1, true); + hpaeSourceProcessCluster->DisConnectInjector(inputNode); + EXPECT_EQ(hpaeSourceProcessCluster->injectorFmtConverterNodeMap_.size() == 0, true); +} } // namespace HPAE } // namespace AudioStandard } // namespace OHOS diff --git a/services/audio_engine/test/unittest/node/hpae_virtual_process_cluster_test.cpp b/services/audio_engine/test/unittest/node/hpae_virtual_process_cluster_test.cpp new file mode 100644 index 0000000000..dd8509a036 --- /dev/null +++ b/services/audio_engine/test/unittest/node/hpae_virtual_process_cluster_test.cpp @@ -0,0 +1,254 @@ +/* + * 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 +#include "audio_errors.h" +#include "hpae_virtual_process_cluster.h" +#include "hpae_mixer_node.h" +#include "hpae_gain_node.h" +#include "hpae_sink_input_node.h" +#include "hpae_audio_format_converter_node.h" +using namespace testing::ext; +using namespace testing; + +namespace OHOS { +namespace AudioStandard { +namespace HPAE { +static constexpr uint32_t DEFAULT_SESSION_ID01 = 100000; +static constexpr uint32_t DEFAULT_SESSION_ID02 = 100001; +class HpaeVirtualProcessClusterTest : public testing::Test { +protected: + void SetUp() override { + nodeInfo_.nodeId = 1; + nodeInfo_.samplingRate = SAMPLE_RATE_48000; + nodeInfo_.frameLen = 960; + nodeInfo_.channels = STEREO; + nodeInfo_.format = SAMPLE_F32LE; + nodeInfo_.sessionId = DEFAULT_SESSION_ID01; + } + + void TearDown() override {} + + HpaeNodeInfo nodeInfo_; +}; + +HWTEST_F(HpaeVirtualProcessClusterTest, ConstructHpaeVirtualProcessCluster, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + + EXPECT_NE(cluster->GetSharedInstance(), nullptr); + std::shared_ptr mixerInstance = cluster->GetSharedInstance(); + EXPECT_NE(mixerInstance, nullptr); + OutputPort* port = cluster->GetOutputPort(); + EXPECT_NE(port, nullptr); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, DestructorCleansUpResources, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + HpaeNodeInfo nodeInfo = nodeInfo_; + nodeInfo.samplingRate = SAMPLE_RATE_44100; + std::shared_ptr preNode = std::make_shared(nodeInfo); + cluster->Connect(preNode); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 1); + +} + +HWTEST_F(HpaeVirtualProcessClusterTest, DoProcessDelegatesToMixerNode, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + EXPECT_NO_FATAL_FAILURE(cluster->DoProcess()); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, ResetClearsMixerNode, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + auto preNode = std::make_shared(nodeInfo_); + cluster->Connect(preNode); + EXPECT_GT(cluster->GetConnectSinkInputNum(), 1); + EXPECT_EQ(cluster->Reset(), true); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 0); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, ResetAllClearsAllConnections, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + + HpaeNodeInfo info1 = nodeInfo_; + info1.sessionId = DEFAULT_SESSION_ID01; + HpaeNodeInfo info2 = nodeInfo_; + info2.sessionId = DEFAULT_SESSION_ID02; + + auto preNode1 = std::make_shared(info1); + auto preNode2 = std::make_shared(info2); + cluster->Connect(preNode1); + cluster->Connect(preNode2); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 2); + cluster->DisConnect(preNode2); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 1); + EXPECT_EQ(cluster->ResetAll(), true); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, GetSharedInstanceReturnsMixerNode, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + EXPECT_NE(cluster->GetSharedInstance()!= nullptr, true); + EXPECT_EQ(cluster->GetSharedInstance()->GetNodeId(), nodeInfo_.nodeId); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, GetOutputPortReturnsMixerPort, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + EXPECT_NE(cluster->GetOutputPort() != nullptr, true); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, ConnectCreatesGainAndConverterNodes, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + HpaeNodeInfo preNodeInfo = nodeInfo_; + preNodeInfo.sessionId = DEFAULT_SESSION_ID01; + auto preNode = std::make_shared(preNodeInfo); + cluster->Connect(preNode); + std::shared_ptr gainNode = cluster->GetGainNodeById(preNodeInfo.sessionId); + EXPECT_NE(gainNode, nullptr); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 1); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, ConnectSameSessionIdNoDuplicates, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + HpaeNodeInfo preNodeInfo = nodeInfo_; + preNodeInfo.sessionId = DEFAULT_SESSION_ID01; + auto preNode = std::make_shared(preNodeInfo); + cluster->Connect(preNode); + size_t initialCount = cluster->GetConnectSinkInputNum(); + cluster->Connect(preNode); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), initialCount); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, DisConnectRemovesNodesFromMaps, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + + HpaeNodeInfo preNodeInfo = nodeInfo_; + preNodeInfo.sessionId = DEFAULT_SESSION_ID01; + auto preNode = std::make_shared(preNodeInfo); + cluster->Connect(preNode); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 1); + std::shared_ptr gainNodeBefore = cluster->GetGainNodeById(preNodeInfo.sessionId); + EXPECT_NE(gainNodeBefore, nullptr); + cluster->DisConnect(preNode); + std::shared_ptr gainNodeAfter = cluster->GetGainNodeById(preNodeInfo.sessionId); + EXPECT_EQ(gainNodeAfter, nullptr); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 0); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, DisConnectNonExistentSession, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + HpaeNodeInfo preNodeInfo = nodeInfo_; + preNodeInfo.sessionId = DEFAULT_SESSION_ID01; + auto preNode = std::make_shared(preNodeInfo); + + EXPECT_NO_FATAL_FAILURE(cluster->DisConnect(preNode)); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, SetupAudioLimiterReturnsSuccess, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + + int32_t result = cluster->SetupAudioLimiter(); + EXPECT_EQ(result, SUCCESS); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, GetConnectSinkInputNumReturnsCorrectCount, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 0); + + HpaeNodeInfo info1 = nodeInfo_; + info1.sessionId = DEFAULT_SESSION_ID01; + HpaeNodeInfo info2 = nodeInfo_; + info2.sessionId = DEFAULT_SESSION_ID02; + + auto preNode1 = std::make_shared(info1); + auto preNode2 = std::make_shared(info2); + + cluster->Connect(preNode1); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 1); + + cluster->Connect(preNode2); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 2); + + cluster->DisConnect(preNode1); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 1); + + cluster->DisConnect(preNode2); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), 0); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, GetGainNodeByIdReturnsCorrectNode, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + + HpaeNodeInfo preNodeInfo = nodeInfo_; + preNodeInfo.sessionId = DEFAULT_SESSION_ID01; + auto preNode = std::make_shared(preNodeInfo); + + cluster->Connect(preNode); + + std::shared_ptr gainNode = cluster->GetGainNodeById(preNodeInfo.sessionId); + EXPECT_NE(gainNode, nullptr); + EXPECT_EQ(gainNode->GetSessionId(), preNodeInfo.sessionId); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, GetGainNodeByIdNonExistentReturnsNull, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + + std::shared_ptr gainNode = cluster->GetGainNodeById(9999); + EXPECT_EQ(gainNode, nullptr); +} + +HWTEST_F(HpaeVirtualProcessClusterTest, MultipleConnectDisconnectOperations, TestSize.Level0) +{ + std::shared_ptr cluster = std::make_shared(nodeInfo_); + const int32_t numOperations = 5; + HpaeNodeInfo preNodeInfo = nodeInfo_; + + for (int32_t i = 0; i < numOperations; i++) { + preNodeInfo.sessionId = DEFAULT_SESSION_ID01 + i; + auto preNode = std::make_shared(preNodeInfo); + cluster->Connect(preNode); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), i + 1); + std::shared_ptr gainNode = cluster->GetGainNodeById(preNodeInfo.sessionId); + EXPECT_NE(gainNode, nullptr); + } + + for (int32_t i = 0; i < numOperations; i++) { + preNodeInfo.sessionId = DEFAULT_SESSION_ID01 + i; + auto preNode = std::make_shared(preNodeInfo); + + cluster->DisConnect(preNode); + EXPECT_EQ(cluster->GetConnectSinkInputNum(), numOperations - i - 1); + std::shared_ptr gainNode = cluster->GetGainNodeById(preNodeInfo.sessionId); + EXPECT_EQ(gainNode, nullptr); + } +} +} // namespace HPAE +} // namespace AudioStandard +} // namespace OHOS \ No newline at end of file diff --git a/test/BUILD.gn b/test/BUILD.gn index 8c1d68c43f..53f7d6d8de 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -105,6 +105,8 @@ group("audio_unit_test") { "../services/audio_engine/test/unittest:hpae_source_input_node_test", "../services/audio_engine/test/unittest:hpae_source_output_node_test", "../services/audio_engine/test/unittest:hpae_source_process_cluster_test", + "../services/audio_engine/test/unittest:hpae_sink_virtual_output_node_test", + "../services/audio_engine/test/unittest:hpae_virtual_process_cluster_test", "../services/audio_policy/test:audio_policy_unittest_packages", "../services/audio_service/test/unittest:audio_balance_unit_test", "../services/audio_service/test/unittest:audio_dump_pcm_unit_test", -- Gitee