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> ×tamp)
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