diff --git a/services/audio_engine/BUILD.gn b/services/audio_engine/BUILD.gn index d22bf8086100242ef5e7535f6e6b7d90327b1a03..31b461d703cdbe69b30633abee37babec53afc19 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 b1ebd3b9d7880389f8eaa70bae78250a924b54e1..2bfd6698dd9c30d0ad8bfa1db45fe5f6b3681f7a 100644 --- a/services/audio_engine/manager/include/hpae_capturer_manager.h +++ b/services/audio_engine/manager/include/hpae_capturer_manager.h @@ -75,6 +75,11 @@ 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_injector_renderer_manager.h b/services/audio_engine/manager/include/hpae_injector_renderer_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..c0d1eb32913cbc1954f8f3f8119c3777fc44a2ce --- /dev/null +++ b/services/audio_engine/manager/include/hpae_injector_renderer_manager.h @@ -0,0 +1,121 @@ +/* + * 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_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/include/hpae_manager.h b/services/audio_engine/manager/include/hpae_manager.h index 82497ab535f29d238d8ae02115b025c43caf0948..a055370ee5b1560fd31989c08e29ebd760dca82f 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 45218dd808c2b95fc8cdeed780f2622146149eb7..0d8b41408e58faef74490606073a8e644fab1265 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 738c08b33ffacbe58af1c1183aa70a47819674bd..92f648a773b42d08a0330693fa41c8d367e75c96 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 25346dc76f8f7619bf60af16cafd3d67e930fea4..81efb0be96470fc6b79faf97160e8cc965c034af 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 3f1872f3299e267d82c76312ae47180bbeac8964..19b3ae4ccd1639dabfae60c500452d963bccaac6 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 d0a4382050297db986df6396223ebac743640bdf..98d7b82261261d285346e96b73511d8dd3874b2b 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 { @@ -108,6 +109,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 55bf50350d1c615764e74478f3b9b918d23cf8e7..fd1806d8dd75e710d32fd907616eebac40702159 100644 --- a/services/audio_engine/manager/src/hpae_capturer_manager.cpp +++ b/services/audio_engine/manager/src/hpae_capturer_manager.cpp @@ -104,9 +104,17 @@ int32_t HpaeCapturerManager::CreateOutputSession(const HpaeStreamInfo &streamInf if (sceneType != HPAE_SCENE_EFFECT_NONE && !SafeGetMap(sceneClusterMap_, sceneType)) { // todo: algorithm instance count control - 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); } } @@ -125,27 +133,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 +275,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; } @@ -875,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) { @@ -1013,6 +1026,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 = SafeGetMap(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 = SafeGetMap(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_injector_renderer_manager.cpp b/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12f5ba62e1f34aa271b79ac3ea6fe6e53ac3cdf0 --- /dev/null +++ b/services/audio_engine/manager/src/hpae_injector_renderer_manager.cpp @@ -0,0 +1,717 @@ +/* + * 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 "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) +{} + +HpaeInjectorRendererManager::~HpaeInjectorRendererManager() +{ + AUDIO_INFO_LOG("destructor injector 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 + 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); + }; + 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) +{ + if (!SafeGetMap(sinkInputNodeMap_, sessionId)) { + return ERR_INVALID_OPERATION; + } + sinkInputInfo.nodeInfo = sinkInputNodeMap_[sessionId]->GetNodeInfo(); + sinkInputInfo.rendererSessionInfo = sessionNodeMap_[sessionId]; + return SUCCESS; +} + +int32_t HpaeInjectorRendererManager::RefreshProcessClusterByDevice() +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +HpaeSinkInfo HpaeInjectorRendererManager::GetSinkInfo() +{ + return sinkInfo_; +} + +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:injector", 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() +{ + Trace trace("HpaeInjectorRendererManager::OnNotifyQueue"); + CHECK_AND_RETURN_LOG(hpaeSignalProcessThread_, "HpaeInjectorRendererManager hpaeSignalProcessThread_ is nullptr"); + 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__, true); + hpaeSignalProcessThread_->ActivateThread(shared_from_this()); + return SUCCESS; +} + +std::string HpaeInjectorRendererManager::GetDeviceHDFDumpInfo() +{ + // todo : hidump info + return ""; +} + +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("HpaeInjectorRendererManager not init, %{public}s excute failed", funcName.c_str()); + return; + } + hpaeNoLockQueue_.PushRequest(std::move(request)); + 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()); + HpaeNodeInfo nodeInfo = sinkOutputNode_ ->GetNodeInfo(); + 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"); + 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; +} + +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 diff --git a/services/audio_engine/manager/src/hpae_manager.cpp b/services/audio_engine/manager/src/hpae_manager.cpp index 9f88e53c5fcfc2e72388802dba5e5fede6468adc..635f3922fd06d04c01c9bd0e1a65d168677fb8fe 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_Injector") { // todo : rewrite correct name + std::lock_guard lock(sinkVirtualOutputNodeMapMutex_); + sinkVirtualOutputNodeMap_[sinkInfo.sinkId] = sinkVirtualOutputNodeMap_[oldId]; + HpaeNodeInfo nodeInfo; + TransSinkInfoToNodeInfo(sinkInfo, rendererManagerMap_[audioModuleInfo.name], nodeInfo); + sinkVirtualOutputNodeMap_[sinkInfo.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 (audioModuleInfo.name == "Virtual_Injector") { // 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_Injector") { + 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_Injector") { + 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 = SafeGetMap(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, rendererManager, 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 = 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(capturerManagerMap_, sourceIdSourceNameMap_[sourcePortIndex]); + CHECK_AND_RETURN_LOG(capturerManager, "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 = 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(capturerManagerMap_, sourceIdSourceNameMap_[sourcePortIndex]); + CHECK_AND_RETURN_LOG(capturerManager, "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 8e4b271c785a1d1c90693599be4cfba651e184b8..6715f0785f671bf193fe7ca2ec8536a3af6b1814 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 d75b20079871dd975876d6831d86a4b48d57512d..e35e907de9a00cdfb2a1d30efa7aecfea347bfaa 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 HpaeVirtualCapturerManager::AddCaptureInjector( + const std::shared_ptr> &sinkOutputNode, const SourceType &sourceType) +{ + AUDIO_ERR_LOG("Unsupported operation"); + return SUCCESS; +} + +int32_t HpaeVirtualCapturerManager::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 edadb35d57a575cee3060de2d5a933b782ed397d..f81ae7e2611522bc4689e4b9c10726c7fb667f9d 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_Injector") { // 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_capture_effect_node.h b/services/audio_engine/node/include/hpae_capture_effect_node.h index 8e872c3a0589f27b13621f835c4bf30c05ceaf96..ce42d3596624053bc9158a3699b2786a63903f34 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_mixer_node.h b/services/audio_engine/node/include/hpae_mixer_node.h index 15f892f885e1f07251133548b9789acf4e659f17..39d439530176bbcddffcb88ac7db28ddf56accab 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 f02e3e809c13a7c18b8a72be0fbff8a3bd495a2b..f3914a6641c7bd99577ce4bcbecbf87595a42acc 100644 --- a/services/audio_engine/node/include/hpae_node_common.h +++ b/services/audio_engine/node/include/hpae_node_common.h @@ -66,6 +66,9 @@ 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); +size_t CaculateFrameLenByNodeInfo(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 0000000000000000000000000000000000000000..da03d6c3c91ad9ac6cc67d594116719c71c3655f --- /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 ce71ae7ad5ede2a0c5a1016a09de1de867278497..fa658b4d32b858c9ada58dfb9ec80d31394c0e92 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,19 +40,28 @@ 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 GetMixerNodeUseCount(); uint32_t GetCapturerEffectNodeUseCount(); uint32_t GetConverterNodeCount(); 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/include/hpae_virtual_process_cluster.h b/services/audio_engine/node/include/hpae_virtual_process_cluster.h new file mode 100644 index 0000000000000000000000000000000000000000..5209c1642f09cb7830d9c4357c6ef333ab0c9c51 --- /dev/null +++ b/services/audio_engine/node/include/hpae_virtual_process_cluster.h @@ -0,0 +1,51 @@ +/* + * 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); + 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_; +}; +} // 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_mixer_node.cpp b/services/audio_engine/node/src/hpae_mixer_node.cpp index 16b2dbdb2f5ec723f23b5f55d3e741b1b53995d0..3470c3f996c3431e89b2dc044d3938cd37fb7360 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 HpaeMixerNode::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 HpaeMixerNode::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 fbb39f815a8acd5669cd1f917bec046be86965f7..0c3a426a8697767426c8d81fbe6aee4f86195781 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; @@ -526,6 +527,25 @@ 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; +} + +size_t CaculateFrameLenByNodeInfo(HpaeNodeInfo &nodeInfo) +{ + return nodeInfo.samplingRate * DEFAULT_FRAME_LEN_MS / MS_PER_SECOND; +} } // 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 0000000000000000000000000000000000000000..4fa198df2dc1d2ed9eca4b38e81bfe56f5582091 --- /dev/null +++ b/services/audio_engine/node/src/hpae_sink_virtual_output_node.cpp @@ -0,0 +1,236 @@ +/* + * 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_BUFFER_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(result.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(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, + AudioStreamInfo &audioStreamInfo) +{ + 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; +} + +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 + if (auto callback = GetNodeStatusCallback().lock()) { + callback->OnNotifyDfxNodeInfo(true, GetNodeId(), preNode->GetSharedInstance()->GetNodeInfo()); + } +#endif +} + +void HpaeSinkVirtualOutputNode::DisConnect(const std::shared_ptr> &preNode) +{ + 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 +} + +StreamManagerState HpaeSinkVirtualOutputNode::GetState() +{ + return state_; +} + +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(); +} + +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 25e27def89d4cb00a3e07d1c969f37b7277a986c..e8f731dd74202d90ecbf446c2df884fa2db9ffbb 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,69 +50,73 @@ 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() { - return captureEffectNode_; + return mixerNode_; } OutputPort *HpaeSourceProcessCluster::GetOutputPort() { - return captureEffectNode_->GetOutputPort(); + return mixerNode_->GetOutputPort(); } std::shared_ptr HpaeSourceProcessCluster::GetSharedInstance(HpaeNodeInfo &nodeInfo) { std::string sourceOutputNodeKey = TransNodeInfoToStringKey(nodeInfo); - HpaeNodeInfo effectNodeInfo; - captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); + HpaeNodeInfo effectNodeInfo = mixerNode_->GetNodeInfo(); 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_; + AUDIO_INFO_LOG("Config of sourceOutputNode is same with capture mixerNode"); + 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]; } OutputPort *HpaeSourceProcessCluster::GetOutputPort(HpaeNodeInfo &nodeInfo, bool isDisConnect) { std::string sourceOutputNodeKey = TransNodeInfoToStringKey(nodeInfo); - HpaeNodeInfo effectNodeInfo; - captureEffectNode_->GetCapturerEffectConfig(effectNodeInfo); + HpaeNodeInfo effectNodeInfo = mixerNode_->GetNodeInfo(); 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_->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(captureEffectNode_); + fmtConverterNodeMap_[sourceOutputNodeKey]->DisConnect(mixerNode_); } return fmtConverterNodeMap_[sourceOutputNodeKey]->GetOutputPort(); } @@ -119,52 +124,124 @@ 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, 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_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_->Connect(preNode); + } else { + injectorFmtConverterNodeMap_[preNode] = + std::make_shared(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_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]->DisConnect(preNode); + mixerNode_->DisConnect(injectorFmtConverterNodeMap_[preNode]); + injectorFmtConverterNodeMap_.erase(preNode); + } } bool HpaeSourceProcessCluster::GetCapturerEffectConfig(HpaeNodeInfo &nodeInfo, HpaeSourceBufferType type) { + if (captureEffectNode_ == nullptr) { + nodeInfo = mixerNode_->GetNodeInfo(); + return true; + } return captureEffectNode_->GetCapturerEffectConfig(nodeInfo, type); } size_t HpaeSourceProcessCluster::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"); - 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::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 new file mode 100644 index 0000000000000000000000000000000000000000..bd2a8d2c31caa37d8c8a2efc115712431092e45d --- /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) + : 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 diff --git a/services/audio_engine/test/unittest/BUILD.gn b/services/audio_engine/test/unittest/BUILD.gn index 6cec754c06aebfc1468eb3a5c10cdf1747fa8e57..37c2221106d0588275b96c72ef5ca01572889dc6 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 f048ec7ffd7a58533c07e98a23db55a7b3ea73d1..a5aaf84ca31210b9cc787ff755d4c05ce4112908 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 c757359e01b5cb6f40495635afbf97076c74873b..f9e5b9a03b3c2aaf99e72270151820adfa0fd749 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,139 @@ 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_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; + 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; + streamInfo2.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_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); + 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_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)); + + 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_); +} + +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 33a716a332b5c7d27e72e4defc8aff62a71dafbb..1df532b6085f0b260cb61b58cea1c137eeeeaf06 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 5f4d7c5c780d8909e83d435b0386ff61a83e3872..de8568fa8d578049c37a5c51451fa3777684c133 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 0000000000000000000000000000000000000000..460a409d04fd6b4f9a92e91d9627e9831bcfd537 --- /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 15f1f923890188e245777c2a777fd48726f09299..224f23cbce97ceba17a710c120f17f70eb6fdf9c 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 0000000000000000000000000000000000000000..dd8509a036038e67ab06c42980822f88b6735226 --- /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 8c1d68c43f9fd229afea6b73d0d7dfbbe7d98cc5..53f7d6d8de1d43b75482bc9b823b7b13ed81561b 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", diff --git a/test/fuzztest/hpaecapturermanager_fuzzer/BUILD.gn b/test/fuzztest/hpaecapturermanager_fuzzer/BUILD.gn index 11a5de8bfa658a83701bced766b868faa536bbd6..cff006973739fdaccc840d94d07f4d04114139f4 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",