1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef LOG_TAG
17 #define LOG_TAG "HpaeRemoteOutputCluster"
18 #endif
19
20 #include <sstream>
21 #include "hpae_remote_output_cluster.h"
22 #include "hpae_node_common.h"
23 #include "audio_errors.h"
24 #include "audio_utils.h"
25 #include "audio_engine_log.h"
26
27 namespace OHOS {
28 namespace AudioStandard {
29 namespace HPAE {
30
HpaeRemoteOutputCluster(HpaeNodeInfo & nodeInfo,HpaeSinkInfo & sinkInfo)31 HpaeRemoteOutputCluster::HpaeRemoteOutputCluster(HpaeNodeInfo &nodeInfo, HpaeSinkInfo &sinkInfo)
32 : HpaeNode(nodeInfo), hpaeSinkOutputNode_(std::make_shared<HpaeRemoteSinkOutputNode>(nodeInfo, sinkInfo))
33 {
34 frameLenMs_ = nodeInfo.frameLen * MILLISECOND_PER_SECOND / nodeInfo.samplingRate;
35 AUDIO_INFO_LOG("HpaeRemoteOutputCluster frameLenMs_:%{public}u ms,"
36 "timeoutThdFrames_:%{public}u", frameLenMs_, timeoutThdFrames_);
37 #ifdef ENABLE_HIDUMP_DFX
38 SetNodeName("HpaeRemoteOutputCluster");
39 #endif
40 }
41
~HpaeRemoteOutputCluster()42 HpaeRemoteOutputCluster::~HpaeRemoteOutputCluster()
43 {
44 Reset();
45 #ifdef ENABLE_HIDUMP_DFX
46 AUDIO_INFO_LOG("NodeId: %{public}u NodeName: %{public}s destructed.",
47 GetNodeId(), GetNodeName().c_str());
48 #endif
49 }
50
DoProcess()51 void HpaeRemoteOutputCluster::DoProcess()
52 {
53 Trace trace("HpaeRemoteOutputCluster::DoProcess");
54 hpaeSinkOutputNode_->DoProcess();
55 std::vector<HpaeProcessorType> needErased;
56 for (auto &mixerNode : sceneMixerMap_) {
57 if (mixerNode.second->GetPreOutNum() == 0) {
58 ++sceneStopCountMap_[mixerNode.first];
59 } else {
60 sceneStopCountMap_[mixerNode.first] = 0;
61 }
62 if (sceneStopCountMap_[mixerNode.first] > timeoutThdFrames_) {
63 needErased.emplace_back(mixerNode.first);
64 hpaeSinkOutputNode_->DisConnect(mixerNode.second);
65 }
66 }
67 for (auto sceneType : needErased) {
68 sceneMixerMap_.erase(sceneType);
69 }
70 if (hpaeSinkOutputNode_->GetPreOutNum() == 0) {
71 int32_t ret = hpaeSinkOutputNode_->RenderSinkStop();
72 AUDIO_INFO_LOG("HpaeRemoteOutputCluster timeout RenderSinkStop ret :%{public}d", ret);
73 }
74 }
75
Reset()76 bool HpaeRemoteOutputCluster::Reset()
77 {
78 hpaeSinkOutputNode_->Reset();
79 for (auto &mixerNode : sceneMixerMap_) {
80 mixerNode.second->Reset();
81 }
82 for (auto converterNode : sceneConverterMap_) {
83 converterNode.second->Reset();
84 }
85 #ifdef ENABLE_HIDUMP_DFX
86 if (auto callBack = hpaeSinkOutputNode_->GetNodeStatusCallback().lock()) {
87 callBack->OnNotifyDfxNodeInfo(false, hpaeSinkOutputNode_->GetNodeId(), hpaeSinkOutputNode_->GetNodeInfo());
88 }
89 #endif
90 return true;
91 }
92
ResetAll()93 bool HpaeRemoteOutputCluster::ResetAll()
94 {
95 return hpaeSinkOutputNode_->ResetAll(); // Complete the code here
96 }
97
Connect(const std::shared_ptr<OutputNode<HpaePcmBuffer * >> & preNode)98 void HpaeRemoteOutputCluster::Connect(const std::shared_ptr<OutputNode<HpaePcmBuffer *>> &preNode)
99 {
100 HpaeNodeInfo &preNodeInfo = preNode->GetSharedInstance()->GetNodeInfo();
101 HpaeNodeInfo nodeInfo = GetNodeInfo();
102 HpaeProcessorType sceneType = preNodeInfo.sceneType;
103 AUDIO_INFO_LOG("HpaeRemoteOutputCluster input sceneType is %{public}u", sceneType);
104 AUDIO_INFO_LOG("HpaeRemoteOutputCluster input rate is %{public}u, ch is %{public}u",
105 preNodeInfo.samplingRate, preNodeInfo.channels);
106 AUDIO_INFO_LOG(" HpaeRemoteOutputCluster output rate is %{public}u, ch is %{public}u",
107 nodeInfo.samplingRate, nodeInfo.channels);
108 AUDIO_INFO_LOG(" HpaeRemoteOutputCluster preNode name %{public}s, curNode name is %{public}s",
109 preNodeInfo.nodeName.c_str(), nodeInfo.nodeName.c_str());
110 nodeInfo.sceneType = sceneType;
111 if (!SafeGetMap(sceneConverterMap_, sceneType)) {
112 sceneConverterMap_[sceneType] = std::make_shared<HpaeAudioFormatConverterNode>(preNodeInfo, nodeInfo);
113 }
114 if (!SafeGetMap(sceneMixerMap_, sceneType)) {
115 sceneMixerMap_[sceneType] = std::make_shared<HpaeMixerNode>(nodeInfo);
116 sceneStopCountMap_[sceneType] = 0;
117 hpaeSinkOutputNode_->Connect(sceneMixerMap_[sceneType]);
118 }
119 sceneMixerMap_[sceneType]->Connect(sceneConverterMap_[sceneType]);
120 sceneConverterMap_[sceneType]->Connect(preNode);
121 connectedProcessCluster_.insert(sceneType);
122 }
123
DisConnect(const std::shared_ptr<OutputNode<HpaePcmBuffer * >> & preNode)124 void HpaeRemoteOutputCluster::DisConnect(const std::shared_ptr<OutputNode<HpaePcmBuffer *>> &preNode)
125 {
126 HpaeNodeInfo &preNodeInfo = preNode->GetSharedInstance()->GetNodeInfo();
127 HpaeProcessorType sceneType = preNodeInfo.sceneType;
128 AUDIO_INFO_LOG("HpaeRemoteOutputCluster input sceneType is %{public}u", preNodeInfo.sceneType);
129 if (SafeGetMap(sceneConverterMap_, sceneType)) {
130 sceneConverterMap_[sceneType]->DisConnect(preNode);
131 sceneMixerMap_[sceneType]->DisConnect(sceneConverterMap_[sceneType]);
132 sceneConverterMap_.erase(sceneType);
133 }
134 connectedProcessCluster_.erase(sceneType);
135 }
136
GetConverterNodeCount()137 int32_t HpaeRemoteOutputCluster::GetConverterNodeCount()
138 {
139 return sceneConverterMap_.size();
140 }
141
GetInstance(const std::string & deviceClass,const std::string & deviceNetId)142 int32_t HpaeRemoteOutputCluster::GetInstance(const std::string &deviceClass, const std::string &deviceNetId)
143 {
144 return hpaeSinkOutputNode_->GetRenderSinkInstance(deviceClass, deviceNetId);
145 }
146
Init(IAudioSinkAttr & attr)147 int32_t HpaeRemoteOutputCluster::Init(IAudioSinkAttr &attr)
148 {
149 return hpaeSinkOutputNode_->RenderSinkInit(attr);
150 }
151
DeInit()152 int32_t HpaeRemoteOutputCluster::DeInit()
153 {
154 return hpaeSinkOutputNode_->RenderSinkDeInit();
155 }
156
Flush(void)157 int32_t HpaeRemoteOutputCluster::Flush(void)
158 {
159 return hpaeSinkOutputNode_->RenderSinkFlush();
160 }
161
Pause(void)162 int32_t HpaeRemoteOutputCluster::Pause(void)
163 {
164 return hpaeSinkOutputNode_->RenderSinkPause();
165 }
166
ResetRender(void)167 int32_t HpaeRemoteOutputCluster::ResetRender(void)
168 {
169 return hpaeSinkOutputNode_->RenderSinkReset();
170 }
171
Resume(void)172 int32_t HpaeRemoteOutputCluster::Resume(void)
173 {
174 return hpaeSinkOutputNode_->RenderSinkResume();
175 }
176
Start(void)177 int32_t HpaeRemoteOutputCluster::Start(void)
178 {
179 return hpaeSinkOutputNode_->RenderSinkStart();
180 }
181
Stop(void)182 int32_t HpaeRemoteOutputCluster::Stop(void)
183 {
184 return hpaeSinkOutputNode_->RenderSinkStop();
185 }
186
GetFrameData(void)187 const char *HpaeRemoteOutputCluster::GetFrameData(void)
188 {
189 return hpaeSinkOutputNode_->GetRenderFrameData();
190 }
191
GetState(void)192 StreamManagerState HpaeRemoteOutputCluster::GetState(void)
193 {
194 return hpaeSinkOutputNode_->GetSinkState();
195 }
196
GetPreOutNum()197 int32_t HpaeRemoteOutputCluster::GetPreOutNum()
198 {
199 return hpaeSinkOutputNode_->GetPreOutNum();
200 }
201
SetTimeoutStopThd(uint32_t timeoutThdMs)202 int32_t HpaeRemoteOutputCluster::SetTimeoutStopThd(uint32_t timeoutThdMs)
203 {
204 if (frameLenMs_ != 0) {
205 timeoutThdFrames_ = timeoutThdMs / frameLenMs_;
206 }
207 AUDIO_INFO_LOG(
208 "SetTimeoutStopThd: timeoutThdFrames_:%{public}u, timeoutThdMs :%{public}u", timeoutThdFrames_, timeoutThdMs);
209 return SUCCESS;
210 }
211
IsProcessClusterConnected(HpaeProcessorType sceneType)212 bool HpaeRemoteOutputCluster::IsProcessClusterConnected(HpaeProcessorType sceneType)
213 {
214 return connectedProcessCluster_.find(sceneType) != connectedProcessCluster_.end();
215 }
216
TransStreamUsageToSplitSceneType(StreamUsage streamUsage,const std::string & splitMode)217 HpaeProcessorType TransStreamUsageToSplitSceneType(StreamUsage streamUsage, const std::string &splitMode)
218 {
219 static constexpr int splitOneStream = 1;
220 static constexpr int splitTwoStream = 2;
221 static constexpr int splitThreeStream = 3;
222 static constexpr int maxParts = 3;
223 AUDIO_INFO_LOG("streamUsage is: %{public}d, splitMode is: %{public}s",
224 static_cast<int>(streamUsage), splitMode.c_str());
225 int splitNums = 0;
226 if (splitMode.empty()) {
227 AUDIO_ERR_LOG("input SPLIT_MODE is empty");
228 return HPAE_SCENE_DEFAULT;
229 }
230 std::istringstream iss(splitMode);
231 std::string token;
232 while (splitNums < maxParts && std::getline(iss, token, ':')) {
233 ++splitNums;
234 }
235 const auto getSceneType = [streamUsage](size_t splitNums) -> HpaeProcessorType {
236 return
237 (splitNums == splitOneStream) ? HPAE_SCENE_SPLIT_MEDIA :
238 (splitNums == splitTwoStream) ? (streamUsage == STREAM_USAGE_NAVIGATION ?
239 HPAE_SCENE_SPLIT_NAVIGATION : HPAE_SCENE_SPLIT_MEDIA) :
240 (splitNums == splitThreeStream) ? (
241 (streamUsage == STREAM_USAGE_NAVIGATION) ? HPAE_SCENE_SPLIT_NAVIGATION :
242 (streamUsage == STREAM_USAGE_VOICE_COMMUNICATION || streamUsage == STREAM_USAGE_VIDEO_COMMUNICATION)
243 ? HPAE_SCENE_SPLIT_COMMUNICATION
244 : HPAE_SCENE_SPLIT_MEDIA
245 ) : HPAE_SCENE_DEFAULT;
246 };
247 return getSceneType(splitNums);
248 }
249
UpdateAppsUid(const std::vector<int32_t> & appsUid)250 int32_t HpaeRemoteOutputCluster::UpdateAppsUid(const std::vector<int32_t> &appsUid)
251 {
252 return hpaeSinkOutputNode_->UpdateAppsUid(appsUid);
253 }
254 } // namespace HPAE
255 } // namespace AudioStandard
256 } // namespace OHOS
257