• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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