• 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 "HpaeSinkInputNode"
18 #endif
19 
20 #include <iostream>
21 #include <cinttypes>
22 #include "hpae_sink_input_node.h"
23 #include "hpae_format_convert.h"
24 #include "hpae_node_common.h"
25 #include "audio_errors.h"
26 #include "audio_utils.h"
27 #include "audio_performance_monitor.h"
28 #include "audio_engine_log.h"
29 
30 namespace OHOS {
31 namespace AudioStandard {
32 namespace HPAE {
33 const std::string DEVICE_CLASS_OFFLOAD = "offload";
34 const std::string DEVICE_CLASS_REMOTE_OFFLOAD = "remote_offload";
35 
HpaeSinkInputNode(HpaeNodeInfo & nodeInfo)36 HpaeSinkInputNode::HpaeSinkInputNode(HpaeNodeInfo &nodeInfo)
37     : HpaeNode(nodeInfo),
38       pcmBufferInfo_(nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate, (uint64_t)nodeInfo.channelLayout),
39       emptyBufferInfo_(nodeInfo.channels, 0, nodeInfo.samplingRate, (uint64_t)nodeInfo.channelLayout),
40       inputAudioBuffer_(pcmBufferInfo_), emptyAudioBuffer_(emptyBufferInfo_), outputStream_(this),
41       interleveData_(nodeInfo.frameLen * nodeInfo.channels * GetSizeFromFormat(nodeInfo.format)), framesWritten_(0),
42       totalFrames_(0)
43 {
44     AUDIO_INFO_LOG("sinkinput sessionId %{public}d, channelcount %{public}d, channelLayout %{public}" PRIu64 ", "
45         "frameLen %{public}d", nodeInfo.sessionId, inputAudioBuffer_.GetChannelCount(),
46         inputAudioBuffer_.GetChannelLayout(), inputAudioBuffer_.GetFrameLen());
47 
48     if (nodeInfo.historyFrameCount > 0) {
49         PcmBufferInfo pcmInfo = PcmBufferInfo{
50             nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate, nodeInfo.channelLayout,
51                 nodeInfo.historyFrameCount};
52         pcmInfo.isMultiFrames = true;
53         historyBuffer_ = std::make_unique<HpaePcmBuffer>(pcmInfo);
54         AUDIO_INFO_LOG("HpaeSinkInputNode::historybuffer created");
55     } else {
56         historyBuffer_ = nullptr;
57     }
58     if (nodeInfo.samplingRate == SAMPLE_RATE_11025) {
59         pullDataFlag_ = true;
60     }
61 #ifdef ENABLE_HIDUMP_DFX
62     SetNodeName("hpaeSinkInputNode");
63 #endif
64 }
65 
~HpaeSinkInputNode()66 HpaeSinkInputNode::~HpaeSinkInputNode()
67 {
68 #ifdef ENABLE_HIDUMP_DFX
69     AUDIO_INFO_LOG("NodeId: %{public}u NodeName: %{public}s destructed.",
70         GetNodeId(), GetNodeName().c_str());
71 #endif
72 }
73 
CheckAndDestroyHistoryBuffer()74 void HpaeSinkInputNode::CheckAndDestroyHistoryBuffer()
75 {
76     HpaeNodeInfo nodeInfo = GetNodeInfo();
77     // historyBuffer_ has no data, check if historyFrameCount is 0 and destroy it
78     if (nodeInfo.historyFrameCount == 0) {
79         if (historyBuffer_) {
80             AUDIO_INFO_LOG("HpaeSinkInputNode::historyBuffer_ useless, destroy it");
81         }
82         historyBuffer_ = nullptr;
83     } else if (historyBuffer_ == nullptr) {  // this case need to create historyBuffer_
84         PcmBufferInfo pcmInfo = PcmBufferInfo{
85             nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate, nodeInfo.channelLayout,
86                 nodeInfo.historyFrameCount};
87         pcmInfo.isMultiFrames = true;
88         historyBuffer_ = std::make_unique<HpaePcmBuffer>(pcmInfo);
89         AUDIO_INFO_LOG("HpaeSinkInputNode::historybuffer created");
90     }
91 }
92 
GetDataFromSharedBuffer()93 int32_t HpaeSinkInputNode::GetDataFromSharedBuffer()
94 {
95     streamInfo_ = {.framesWritten = framesWritten_,
96         .hdiFramePosition = hdiFramePosition_.exchange(0),
97         .latency = streamInfo_.latency,
98         .inputData = interleveData_.data(),
99         .requestDataLen = interleveData_.size(),
100         .deviceClass = GetDeviceClass(),
101         .deviceNetId = GetDeviceNetId(),
102         .needData = !(historyBuffer_ && historyBuffer_->GetCurFrames()),
103         // offload enbale, underrun 9 times, request force write data; 9 times about 40ms
104         .forceData = offloadEnable_ ? (standbyCounter_ > 9 ? true : false) : true};
105     GetCurrentPosition(streamInfo_.framePosition, streamInfo_.timestamp);
106     auto writeCallback = writeCallback_.lock();
107     if (writeCallback != nullptr) {
108         return writeCallback->OnStreamData(streamInfo_);
109     }
110     AUDIO_ERR_LOG("sessionId: %{public}d, writeCallback is nullptr", GetSessionId());
111     return ERROR;
112 }
113 
ReadToAudioBuffer(int32_t & ret)114 bool HpaeSinkInputNode::ReadToAudioBuffer(int32_t &ret)
115 {
116     auto nodeCallback = GetNodeStatusCallback().lock();
117     if (nodeCallback) {
118         nodeCallback->OnRequestLatency(GetSessionId(), streamInfo_.latency);
119     }
120     if ((GetDeviceClass() == DEVICE_CLASS_OFFLOAD || GetDeviceClass() == DEVICE_CLASS_REMOTE_OFFLOAD) &&
121         !offloadEnable_) {
122         ret = ERR_OPERATION_FAILED;
123         AUDIO_WARNING_LOG("The session %{public}u offloadEnable is false, not request data", GetSessionId());
124     } else {
125         ret = GetDataFromSharedBuffer();
126         if (GetSampleRate() == SAMPLE_RATE_11025) { // for 11025, skip pull data next time
127             pullDataFlag_ = false;
128         }
129         // if historyBuffer has enough data, write to outputStream
130         if (!streamInfo_.needData && historyBuffer_) {
131             historyBuffer_->GetFrameData(inputAudioBuffer_);
132             outputStream_.WriteDataToOutput(&inputAudioBuffer_);
133             inputAudioBuffer_.SetBufferValid(true); // historyBuffer always valid
134             return false; // do not continue in DoProcess!
135         }
136         CheckAndDestroyHistoryBuffer();
137         if (nodeCallback && ret) {
138             nodeCallback->OnNodeStatusUpdate(GetSessionId(), OPERATION_UNDERFLOW);
139             if (isDrain_) {
140                 AUDIO_INFO_LOG("OnNodeStatusUpdate Drain sessionId:%{public}u", GetSessionId());
141                 nodeCallback->OnNodeStatusUpdate(GetSessionId(), OPERATION_DRAINED);
142                 isDrain_ = false;
143             }
144             standbyCounter_++;
145         } else {
146             standbyCounter_ = 0;
147         }
148     }
149     inputAudioBuffer_.SetBufferValid(ret ? false : true);
150     return true; // continue in DoProcess!
151 }
152 
DoProcess()153 void HpaeSinkInputNode::DoProcess()
154 {
155     Trace trace("[" + std::to_string(GetSessionId()) + "]HpaeSinkInputNode::DoProcess " + GetTraceInfo());
156     if (GetSampleRate() == SAMPLE_RATE_11025 && !pullDataFlag_) {
157         // for 11025 input sample rate, pull 40ms data at a time, so pull once each two DoProcess()
158         pullDataFlag_ = true;
159         outputStream_.WriteDataToOutput(&emptyAudioBuffer_);
160         return;
161     }
162 
163     int32_t ret = SUCCESS;
164 
165     if (!ReadToAudioBuffer(ret)) {
166         return;
167     }
168 
169     ConvertToFloat(
170         GetBitWidth(), GetChannelCount() * GetFrameLen(), interleveData_.data(), inputAudioBuffer_.GetPcmDataBuffer());
171     AudioPipeType  pipeType = ConvertDeviceClassToPipe(GetDeviceClass());
172     if (ret != 0) {
173         if (pipeType != PIPE_TYPE_UNKNOWN) {
174             AudioPerformanceMonitor::GetInstance().RecordSilenceState(GetSessionId(), true, pipeType,
175                 static_cast<uint32_t>(appUid_));
176         }
177         Trace underflowTrace("[" + std::to_string(GetSessionId()) + "]HpaeSinkInputNode::DoProcess underflow");
178         memset_s(inputAudioBuffer_.GetPcmDataBuffer(), inputAudioBuffer_.Size(), 0, inputAudioBuffer_.Size());
179     } else {
180         if (pipeType != PIPE_TYPE_UNKNOWN) {
181             AudioPerformanceMonitor::GetInstance().RecordSilenceState(GetSessionId(), false, pipeType,
182                 static_cast<uint32_t>(appUid_));
183         }
184         totalFrames_ = totalFrames_ + GetFrameLen();
185         framesWritten_ = totalFrames_;
186         if (historyBuffer_) {
187             historyBuffer_->StoreFrameData(inputAudioBuffer_);
188         }
189     }
190     outputStream_.WriteDataToOutput(&inputAudioBuffer_);
191 }
192 
Reset()193 bool HpaeSinkInputNode::Reset()
194 {
195     return true;
196 }
197 
ResetAll()198 bool HpaeSinkInputNode::ResetAll()
199 {
200     return true;
201 }
202 
GetSharedInstance()203 std::shared_ptr<HpaeNode> HpaeSinkInputNode::GetSharedInstance()
204 {
205     return shared_from_this();
206 }
207 
GetOutputPort()208 OutputPort<HpaePcmBuffer *> *HpaeSinkInputNode::GetOutputPort()
209 {
210     return &outputStream_;
211 }
212 
RegisterWriteCallback(const std::weak_ptr<IStreamCallback> & callback)213 bool HpaeSinkInputNode::RegisterWriteCallback(const std::weak_ptr<IStreamCallback> &callback)
214 {
215     writeCallback_ = callback;
216     return true;
217 }
218 // reset historyBuffer
Flush()219 void HpaeSinkInputNode::Flush()
220 {
221     if (GetNodeInfo().historyFrameCount == 0) {
222         historyBuffer_ = nullptr;
223     } else if (historyBuffer_ && historyBuffer_->GetFrames() == GetNodeInfo().historyFrameCount) {
224         historyBuffer_->Reset();
225     } else {
226         HpaeNodeInfo nodeInfo = GetNodeInfo();
227         PcmBufferInfo pcmInfo = PcmBufferInfo{
228             nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate, nodeInfo.channelLayout,
229                 nodeInfo.historyFrameCount};
230         pcmInfo.isMultiFrames = true;
231         historyBuffer_ = std::make_unique<HpaePcmBuffer>(pcmInfo);
232     }
233 }
234 
Drain()235 bool HpaeSinkInputNode::Drain()
236 {
237     isDrain_ = true;
238     return true;
239 }
240 
SetState(HpaeSessionState renderState)241 int32_t HpaeSinkInputNode::SetState(HpaeSessionState renderState)
242 {
243     AUDIO_INFO_LOG("Sink[%{public}s]->Session[%{public}u - %{public}d] state change:[%{public}s]-->[%{public}s]",
244         GetDeviceClass().c_str(), GetSessionId(), GetStreamType(), ConvertSessionState2Str(state_).c_str(),
245         ConvertSessionState2Str(renderState).c_str());
246     state_ = renderState;
247     return SUCCESS;
248 }
249 
GetState()250 HpaeSessionState HpaeSinkInputNode::GetState()
251 {
252     return state_;
253 }
254 
SetAppUid(int32_t appUid)255 void HpaeSinkInputNode::SetAppUid(int32_t appUid)
256 {
257     appUid_ = appUid;
258 }
259 
GetAppUid()260 int32_t HpaeSinkInputNode::GetAppUid()
261 {
262     return appUid_;
263 }
264 
GetFramesWritten()265 uint64_t HpaeSinkInputNode::GetFramesWritten()
266 {
267     return framesWritten_;
268 }
269 
GetCurrentPosition(uint64_t & framePosition,std::vector<uint64_t> & timestamp)270 int32_t HpaeSinkInputNode::GetCurrentPosition(uint64_t &framePosition, std::vector<uint64_t> &timestamp)
271 {
272     framePosition = GetFramesWritten();
273     if (historyBuffer_) {
274         framePosition = framePosition > historyBuffer_->GetCurFrames() * GetFrameLen()
275                             ? framePosition - historyBuffer_->GetCurFrames() * GetFrameLen()
276                             : 0;
277     }
278     ClockTime::GetAllTimeStamp(timestamp);
279     return SUCCESS;
280 }
281 
RewindHistoryBuffer(uint64_t rewindTime,uint64_t hdiFramePosition)282 int32_t HpaeSinkInputNode::RewindHistoryBuffer(uint64_t rewindTime, uint64_t hdiFramePosition)
283 {
284     CHECK_AND_RETURN_RET_LOG(historyBuffer_, ERROR, "historyBuffer_ is nullptr");
285     hdiFramePosition_.store(hdiFramePosition);
286     AUDIO_INFO_LOG("HpaeSinkInputNode::rewind %{public}zu frames", ConvertUsToFrameCount(rewindTime, GetNodeInfo()));
287     return historyBuffer_->RewindBuffer(ConvertUsToFrameCount(rewindTime, GetNodeInfo()));
288 }
289 
SetOffloadEnabled(bool offloadEnable)290 void HpaeSinkInputNode::SetOffloadEnabled(bool offloadEnable)
291 {
292     offloadEnable_ = offloadEnable;
293 }
294 
GetOffloadEnabled()295 bool HpaeSinkInputNode::GetOffloadEnabled()
296 {
297     return offloadEnable_;
298 }
299 
SetLoudnessGain(float loudnessGain)300 int32_t HpaeSinkInputNode::SetLoudnessGain(float loudnessGain)
301 {
302     loudnessGain_ = loudnessGain;
303     return SUCCESS;
304 }
305 
GetLoudnessGain()306 float HpaeSinkInputNode::GetLoudnessGain()
307 {
308     return loudnessGain_;
309 }
310 
SetSpeed(float speed)311 void HpaeSinkInputNode::SetSpeed(float speed)
312 {
313     speed_ = speed;
314 }
315 
GetSpeed()316 float HpaeSinkInputNode::GetSpeed()
317 {
318     return speed_;
319 }
320 }  // namespace HPAE
321 }  // namespace AudioStandard
322 }  // namespace OHOS