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 "HpaeRemoteSinkOutputNode"
18 #endif
19
20 #include <iostream>
21 #include "hpae_remote_sink_output_node.h"
22 #include "audio_errors.h"
23 #include "hpae_format_convert.h"
24 #include "audio_utils.h"
25 #include "hpae_node_common.h"
26 #include "audio_engine_log.h"
27
28 namespace OHOS {
29 namespace AudioStandard {
30 namespace HPAE {
31
HpaeRemoteSinkOutputNode(HpaeNodeInfo & nodeInfo,HpaeSinkInfo & sinkInfo)32 HpaeRemoteSinkOutputNode::HpaeRemoteSinkOutputNode(HpaeNodeInfo &nodeInfo, HpaeSinkInfo &sinkInfo)
33 : HpaeNode(nodeInfo),
34 renderFrameData_(nodeInfo.frameLen * nodeInfo.channels * GetSizeFromFormat(nodeInfo.format)),
35 interleveData_(nodeInfo.frameLen * nodeInfo.channels),
36 needEmptyChunk_(sinkInfo.needEmptyChunk)
37 {
38 #ifdef ENABLE_HOOK_PCM
39 outputMediaPcmDumper_ = std::make_unique<HpaePcmDumper>("HpaeRemoteSinkOutputNode_Out_Media_bit_" +
40 std::to_string(GetBitWidth()) + "_ch_" + std::to_string(GetChannelCount()) + "_rate_" +
41 std::to_string(GetSampleRate()) + ".pcm");
42 outputNavigationPcmDumper_ = std::make_unique<HpaePcmDumper>("HpaeRemoteSinkOutputNode_Out_Navigation_bit_" +
43 std::to_string(GetBitWidth()) + "_ch_" + std::to_string(GetChannelCount()) + "_rate_" +
44 std::to_string(GetSampleRate()) + ".pcm");
45 outputCommunicationPcmDumper_ = std::make_unique<HpaePcmDumper>("HpaeRemoteSinkOutputNode_Out_Communication_bit_" +
46 std::to_string(GetBitWidth()) + "_ch_" + std::to_string(GetChannelCount()) + "_rate_" +
47 std::to_string(GetSampleRate()) + ".pcm");
48 AUDIO_INFO_LOG("HpaeRemoteSinkOutputNode name is %{public}s", sinkOutAttr_.adapterName.c_str());
49 #endif
50 #ifdef ENABLE_HIDUMP_DFX
51 SetNodeName("hpaeRemoteSinkOutputNode");
52 if (auto callback = GetNodeStatusCallback().lock()) {
53 callback->OnNotifyDfxNodeInfo(true, 0, GetNodeInfo());
54 }
55 #endif
56 }
57
~HpaeRemoteSinkOutputNode()58 HpaeRemoteSinkOutputNode::~HpaeRemoteSinkOutputNode()
59 {
60 #ifdef ENABLE_HIDUMP_DFX
61 AUDIO_INFO_LOG("NodeId: %{public}u NodeName: %{public}s destructed.",
62 GetNodeId(), GetNodeName().c_str());
63 #endif
64 }
65
HandleRemoteTiming()66 void HpaeRemoteSinkOutputNode::HandleRemoteTiming()
67 {
68 auto now = std::chrono::high_resolution_clock::now();
69 remoteTimePoint_ += std::chrono::milliseconds(20); // 20ms frameLen, need optimize
70 if (remoteTimePoint_ > now) {
71 remoteSleepTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(remoteTimePoint_ - now);
72 } else {
73 remoteSleepTime_ = std::chrono::milliseconds(0);
74 }
75 std::this_thread::sleep_for(remoteSleepTime_);
76 AUDIO_DEBUG_LOG("remoteSleepTime_ %{public}lld", remoteSleepTime_.count());
77 }
78
HandlePcmDumping(HpaeSplitStreamType streamType,char * data,size_t size)79 void HpaeRemoteSinkOutputNode::HandlePcmDumping(HpaeSplitStreamType streamType, char* data, size_t size)
80 {
81 auto handleDump = [&](auto& dumper) {
82 if (dumper) {
83 dumper->CheckAndReopenHandle();
84 dumper->Dump(reinterpret_cast<int8_t*>(data), size);
85 }
86 };
87
88 switch (streamType) {
89 case HpaeSplitStreamType::STREAM_TYPE_MEDIA:
90 handleDump(outputMediaPcmDumper_);
91 break;
92 case HpaeSplitStreamType::STREAM_TYPE_NAVIGATION:
93 handleDump(outputNavigationPcmDumper_);
94 break;
95 default:
96 handleDump(outputCommunicationPcmDumper_);
97 break;
98 }
99 }
100
DoProcess()101 void HpaeRemoteSinkOutputNode::DoProcess()
102 {
103 auto rate = "rate[" + std::to_string(GetSampleRate()) + "]_";
104 auto ch = "ch[" + std::to_string(GetChannelCount()) + "]_";
105 auto len = "len[" + std::to_string(GetFrameLen()) + "]_";
106 auto format = "bit[" + std::to_string(GetBitWidth()) + "]";
107 Trace trace("HpaeRemoteSinkOutputNode::DoProcess " + rate + ch + len + format);
108 if (audioRendererSink_ == nullptr) {
109 AUDIO_WARNING_LOG("audioRendererSink_ is nullptr sessionId: %{public}u", GetSessionId());
110 return;
111 }
112 std::vector<HpaePcmBuffer *> &outputVec = inputStream_.ReadPreOutputData();
113 for (auto &outputData : outputVec) {
114 if (outputData == nullptr || (!outputData->IsValid() && !needEmptyChunk_)) {
115 continue;
116 }
117 HpaeSplitStreamType streamType = outputData->GetSplitStreamType();
118 ConvertFromFloat(
119 GetBitWidth(), GetChannelCount() * GetFrameLen(), outputData->GetPcmDataBuffer(), renderFrameData_.data());
120 uint64_t writeLen = 0;
121 char *renderFrameData = (char *)renderFrameData_.data();
122 #ifdef ENABLE_HOOK_PCM
123 HandlePcmDumping(streamType, renderFrameData, renderFrameData_.size());
124 #endif
125 auto ret = audioRendererSink_->SplitRenderFrame(*renderFrameData, renderFrameData_.size(),
126 writeLen, std::to_string(static_cast<int>(streamType)).c_str());
127 if (ret != SUCCESS || writeLen != renderFrameData_.size()) {
128 AUDIO_ERR_LOG("HpaeRemoteSinkOutputNode: RenderFrame failed, SplitStreamType %{public}d", streamType);
129 }
130 }
131 HandleRemoteTiming(); // used to control remote RenderFrame tempo.
132 return;
133 }
134
GetRenderFrameData(void)135 const char *HpaeRemoteSinkOutputNode::GetRenderFrameData(void)
136 {
137 return renderFrameData_.data();
138 }
139
Reset()140 bool HpaeRemoteSinkOutputNode::Reset()
141 {
142 const auto preOutputMap = inputStream_.GetPreOutputMap();
143 for (const auto &preOutput : preOutputMap) {
144 OutputPort<HpaePcmBuffer *> *output = preOutput.first;
145 inputStream_.DisConnect(output);
146 }
147 return true;
148 }
149
ResetAll()150 bool HpaeRemoteSinkOutputNode::ResetAll()
151 {
152 const auto preOutputMap = inputStream_.GetPreOutputMap();
153 for (const auto &preOutput : preOutputMap) {
154 OutputPort<HpaePcmBuffer *> *output = preOutput.first;
155 std::shared_ptr<HpaeNode> hpaeNode = preOutput.second;
156 if (hpaeNode->ResetAll()) {
157 inputStream_.DisConnect(output);
158 }
159 }
160 return true;
161 }
162
Connect(const std::shared_ptr<OutputNode<HpaePcmBuffer * >> & preNode)163 void HpaeRemoteSinkOutputNode::Connect(const std::shared_ptr<OutputNode<HpaePcmBuffer *>> &preNode)
164 {
165 inputStream_.Connect(preNode->GetSharedInstance(), preNode->GetOutputPort());
166 #ifdef ENABLE_HIDUMP_DFX
167 if (auto callback = GetNodeStatusCallback().lock()) {
168 callback->OnNotifyDfxNodeInfo(true, GetNodeId(), preNode->GetSharedInstance()->GetNodeInfo());
169 }
170 #endif
171 }
172
DisConnect(const std::shared_ptr<OutputNode<HpaePcmBuffer * >> & preNode)173 void HpaeRemoteSinkOutputNode::DisConnect(const std::shared_ptr<OutputNode<HpaePcmBuffer *>> &preNode)
174 {
175 inputStream_.DisConnect(preNode->GetOutputPort());
176 #ifdef ENABLE_HIDUMP_DFX
177 if (auto callback = GetNodeStatusCallback().lock()) {
178 auto preNodeReal = preNode->GetSharedInstance();
179 callback->OnNotifyDfxNodeInfo(false, preNodeReal->GetNodeId(), preNodeReal->GetNodeInfo());
180 }
181 #endif
182 }
183
GetRenderSinkInstance(const std::string & deviceClass,const std::string & deviceNetId)184 int32_t HpaeRemoteSinkOutputNode::GetRenderSinkInstance(const std::string &deviceClass, const std::string &deviceNetId)
185 {
186 if (deviceNetId.empty()) {
187 renderId_ = HdiAdapterManager::GetInstance().GetRenderIdByDeviceClass(deviceClass, HDI_ID_INFO_DEFAULT, true);
188 } else {
189 renderId_ = HdiAdapterManager::GetInstance().GetRenderIdByDeviceClass(deviceClass, deviceNetId, true);
190 }
191 audioRendererSink_ = HdiAdapterManager::GetInstance().GetRenderSink(renderId_, true);
192 if (audioRendererSink_ == nullptr) {
193 AUDIO_ERR_LOG("get sink fail, deviceClass: %{public}s, deviceNetId: %{public}s, renderId_: %{public}u",
194 deviceClass.c_str(),
195 deviceNetId.c_str(),
196 renderId_);
197 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
198 return ERROR;
199 }
200 return SUCCESS;
201 }
202
RenderSinkInit(IAudioSinkAttr & attr)203 int32_t HpaeRemoteSinkOutputNode::RenderSinkInit(IAudioSinkAttr &attr)
204 {
205 if (audioRendererSink_ == nullptr) {
206 return ERROR;
207 }
208
209 sinkOutAttr_ = attr;
210 if (audioRendererSink_->IsInited()) {
211 AUDIO_WARNING_LOG("audioRenderSink already inited");
212 SetSinkState(STREAM_MANAGER_IDLE);
213 return SUCCESS;
214 }
215 #ifdef ENABLE_HOOK_PCM
216 HighResolutionTimer timer;
217 timer.Start();
218 #endif
219 int32_t ret = audioRendererSink_->Init(attr);
220 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret,
221 "audioRendererSink_ init failed, errCode is %{public}d", ret);
222 SetSinkState(STREAM_MANAGER_IDLE);
223 #ifdef ENABLE_HOOK_PCM
224 timer.Stop();
225 int64_t interval = timer.Elapsed();
226 AUDIO_INFO_LOG("HpaeRemoteSinkOutputNode: name %{public}s, RenderSinkInit Elapsed: %{public}" PRId64
227 " ms ret: %{public}d",
228 sinkOutAttr_.adapterName.c_str(),
229 interval,
230 ret);
231 std::string adapterName = sinkOutAttr_.adapterName;
232 outputMediaPcmDumper_ = std::make_unique<HpaePcmDumper>(
233 "HpaeRemoteSinkOutputNode_Media_" + adapterName + "_bit_" + std::to_string(GetBitWidth()) + "_ch_" +
234 std::to_string(GetChannelCount()) + "_rate_" + std::to_string(GetSampleRate()) + ".pcm");
235 outputNavigationPcmDumper_ = std::make_unique<HpaePcmDumper>(
236 "HpaeRemoteSinkOutputNode_Navigation_" + adapterName + "_bit_" + std::to_string(GetBitWidth()) + "_ch_" +
237 std::to_string(GetChannelCount()) + "_rate_" + std::to_string(GetSampleRate()) + ".pcm");
238 outputCommunicationPcmDumper_ = std::make_unique<HpaePcmDumper>(
239 "HpaeRemoteSinkOutputNode_Communication_" + adapterName + "_bit_" + std::to_string(GetBitWidth()) + "_ch_" +
240 std::to_string(GetChannelCount()) + "_rate_" + std::to_string(GetSampleRate()) + ".pcm");
241 #endif
242 return ret;
243 }
244
RenderSinkDeInit(void)245 int32_t HpaeRemoteSinkOutputNode::RenderSinkDeInit(void)
246 {
247 if (audioRendererSink_ == nullptr) {
248 return ERROR;
249 }
250 SetSinkState(STREAM_MANAGER_RELEASED);
251 #ifdef ENABLE_HOOK_PCM
252 HighResolutionTimer timer;
253 timer.Start();
254 #endif
255 audioRendererSink_->DeInit();
256 audioRendererSink_ = nullptr;
257 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
258 #ifdef ENABLE_HOOK_PCM
259 timer.Stop();
260 int64_t interval = timer.Elapsed();
261 AUDIO_INFO_LOG("HpaeRemoteSinkOutputNode: name %{public}s, RenderSinkDeInit Elapsed: %{public}" PRId64 " ms",
262 sinkOutAttr_.adapterName.c_str(),
263 interval);
264 #endif
265 return SUCCESS;
266 }
267
RenderSinkFlush(void)268 int32_t HpaeRemoteSinkOutputNode::RenderSinkFlush(void)
269 {
270 if (audioRendererSink_ == nullptr) {
271 return ERROR;
272 }
273 return audioRendererSink_->Flush();
274 }
275
RenderSinkPause(void)276 int32_t HpaeRemoteSinkOutputNode::RenderSinkPause(void)
277 {
278 if (audioRendererSink_ == nullptr) {
279 return ERROR;
280 }
281 audioRendererSink_->Pause();
282 SetSinkState(STREAM_MANAGER_SUSPENDED);
283 return SUCCESS;
284 }
285
RenderSinkReset(void)286 int32_t HpaeRemoteSinkOutputNode::RenderSinkReset(void)
287 {
288 if (audioRendererSink_ == nullptr) {
289 return ERROR;
290 }
291 return audioRendererSink_->Reset();
292 }
293
RenderSinkResume(void)294 int32_t HpaeRemoteSinkOutputNode::RenderSinkResume(void)
295 {
296 if (audioRendererSink_ == nullptr) {
297 return ERROR;
298 }
299 int32_t ret = audioRendererSink_->Resume();
300 if (ret != SUCCESS) {
301 return ret;
302 }
303 SetSinkState(STREAM_MANAGER_RUNNING);
304 return SUCCESS;
305 }
306
RenderSinkStart(void)307 int32_t HpaeRemoteSinkOutputNode::RenderSinkStart(void)
308 {
309 if (audioRendererSink_ == nullptr) {
310 return ERROR;
311 }
312
313 int32_t ret;
314 #ifdef ENABLE_HOOK_PCM
315 HighResolutionTimer timer;
316 timer.Start();
317 #endif
318 ret = audioRendererSink_->Start();
319 if (ret != SUCCESS) {
320 return ERROR;
321 }
322 #ifdef ENABLE_HOOK_PCM
323 timer.Stop();
324 int64_t interval = timer.Elapsed();
325 AUDIO_INFO_LOG("HpaeRemoteSinkOutputNode: name %{public}s, RenderSinkStart Elapsed: %{public}" PRId64 " ms",
326 sinkOutAttr_.adapterName.c_str(),
327 interval);
328 #endif
329 SetSinkState(STREAM_MANAGER_RUNNING);
330 remoteTimePoint_ = std::chrono::high_resolution_clock::now();
331 return SUCCESS;
332 }
333
RenderSinkStop(void)334 int32_t HpaeRemoteSinkOutputNode::RenderSinkStop(void)
335 {
336 if (audioRendererSink_ == nullptr) {
337 return ERROR;
338 }
339 SetSinkState(STREAM_MANAGER_SUSPENDED);
340 int32_t ret;
341 #ifdef ENABLE_HOOK_PCM
342 HighResolutionTimer timer;
343 timer.Start();
344 #endif
345 ret = audioRendererSink_->Stop();
346 if (ret != SUCCESS) {
347 return ret;
348 }
349 #ifdef ENABLE_HOOK_PCM
350 timer.Stop();
351 int64_t interval = timer.Elapsed();
352 AUDIO_INFO_LOG("HpaeRemoteSinkOutputNode: name %{public}s, RenderSinkStop Elapsed: %{public}" PRId64 " ms",
353 sinkOutAttr_.adapterName.c_str(), interval);
354 #endif
355 return SUCCESS;
356 }
357
GetSinkState(void)358 StreamManagerState HpaeRemoteSinkOutputNode::GetSinkState(void)
359 {
360 return state_;
361 }
362
SetSinkState(StreamManagerState sinkState)363 int32_t HpaeRemoteSinkOutputNode::SetSinkState(StreamManagerState sinkState)
364 {
365 AUDIO_INFO_LOG("Sink[%{public}s] state change:[%{public}s]-->[%{public}s]",
366 GetDeviceClass().c_str(), ConvertStreamManagerState2Str(state_).c_str(),
367 ConvertStreamManagerState2Str(sinkState).c_str());
368 state_ = sinkState;
369 return SUCCESS;
370 }
371
GetPreOutNum()372 size_t HpaeRemoteSinkOutputNode::GetPreOutNum()
373 {
374 return inputStream_.GetPreOutputNum();
375 }
376
UpdateAppsUid(const std::vector<int32_t> & appsUid)377 int32_t HpaeRemoteSinkOutputNode::UpdateAppsUid(const std::vector<int32_t> &appsUid)
378 {
379 CHECK_AND_RETURN_RET_LOG(audioRendererSink_ != nullptr, ERROR, "audioRendererSink_ is nullptr");
380 CHECK_AND_RETURN_RET_LOG(audioRendererSink_->IsInited(), ERR_ILLEGAL_STATE, "audioRendererSink_ not init");
381 return audioRendererSink_->UpdateAppsUid(appsUid);
382 }
383 } // namespace HPAE
384 } // namespace AudioStandard
385 } // namespace OHOS
386