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 "HpaeGainNode"
18 #endif
19
20 #include <algorithm>
21 #include <cmath>
22 #include "hpae_gain_node.h"
23 #include "hpae_pcm_buffer.h"
24 #include "audio_volume.h"
25 #include "audio_utils.h"
26 #include "securec.h"
27 #include "volume_tools_c.h"
28 #include "audio_stream_info.h"
29 #include "hpae_info.h"
30 #include "audio_engine_log.h"
31
32 namespace OHOS {
33 namespace AudioStandard {
34 namespace HPAE {
35
36 static constexpr float FADE_LOW = 0.0f;
37 static constexpr float FADE_HIGH = 1.0f;
38 static constexpr float SHORT_FADE_PERIOD = 0.005f; // 5ms fade for 10ms < playback duration <= 40ms
39 static constexpr float EPSILON = 1e-6f;
40
HpaeGainNode(HpaeNodeInfo & nodeInfo)41 HpaeGainNode::HpaeGainNode(HpaeNodeInfo &nodeInfo) : HpaeNode(nodeInfo), HpaePluginNode(nodeInfo)
42 {
43 isInnerCapturer_ = !GetDeviceClass().compare(0, strlen(INNER_CAPTURER_SINK), INNER_CAPTURER_SINK);
44 auto audioVolume = AudioVolume::GetInstance();
45 float curSystemGain = 1.0f;
46 if (isInnerCapturer_) {
47 curSystemGain = audioVolume->GetStreamVolume(GetSessionId());
48 } else {
49 struct VolumeValues volumes;
50 curSystemGain = audioVolume->GetVolume(GetSessionId(), GetStreamType(), GetDeviceClass(), &volumes);
51 }
52 audioVolume->SetHistoryVolume(GetSessionId(), curSystemGain);
53 audioVolume->Monitor(GetSessionId(), true);
54 AUDIO_INFO_LOG("HpaeGainNode curSystemGain:%{public}f streamType :%{public}d", curSystemGain, GetStreamType());
55 AUDIO_INFO_LOG(
56 "HpaeGainNode SessionId:%{public}u deviceClass :%{public}s", GetSessionId(), GetDeviceClass().c_str());
57 #ifdef ENABLE_HOOK_PCM
58 outputPcmDumper_ = std::make_unique<HpaePcmDumper>("HpaeGainNodeOut_id_" + std::to_string(GetSessionId()) + "_ch_" +
59 std::to_string(GetChannelCount()) + "_rate_" +
60 std::to_string(GetSampleRate()) + "_" + GetTime() + ".pcm");
61 #endif
62 #ifdef ENABLE_HIDUMP_DFX
63 SetNodeName("hpaeGainNode");
64 #endif
65 }
66
~HpaeGainNode()67 HpaeGainNode::~HpaeGainNode()
68 {
69 #ifdef ENABLE_HIDUMP_DFX
70 AUDIO_INFO_LOG("NodeId: %{public}u NodeName: %{public}s destructed.",
71 GetNodeId(), GetNodeName().c_str());
72 #endif
73 }
74
SignalProcess(const std::vector<HpaePcmBuffer * > & inputs)75 HpaePcmBuffer *HpaeGainNode::SignalProcess(const std::vector<HpaePcmBuffer *> &inputs)
76 {
77 if (inputs.empty()) {
78 AUDIO_WARNING_LOG("HpaeGainNode inputs size is empty, SessionId:%{public}d", GetSessionId());
79 return nullptr;
80 }
81 auto rate = "rate[" + std::to_string(inputs[0]->GetSampleRate()) + "]_";
82 auto ch = "ch[" + std::to_string(inputs[0]->GetChannelCount()) + "]_";
83 auto len = "len[" + std::to_string(inputs[0]->GetFrameLen()) + "]";
84 Trace trace("[" + std::to_string(GetSessionId()) + "]HpaeGainNode::SignalProcess " + rate + ch + len);
85 if (fadeOutState_ == FadeOutState::DONE_FADEOUT) {
86 AUDIO_INFO_LOG("HpaeGainNode: fadeout done, set session %{public}d silence", GetSessionId());
87 SilenceData(inputs[0]);
88 }
89 float *inputData = (float *)inputs[0]->GetPcmDataBuffer();
90 uint32_t frameLen = inputs[0]->GetFrameLen();
91 uint32_t channelCount = inputs[0]->GetChannelCount();
92
93 if (needGainState_) {
94 DoGain(inputs[0], frameLen, channelCount);
95 }
96 DoFading(inputs[0]);
97
98 #ifdef ENABLE_HOOK_PCM
99 if (outputPcmDumper_ != nullptr) {
100 outputPcmDumper_->Dump((int8_t *)(inputData), (frameLen * sizeof(float) * channelCount));
101 }
102 #endif
103 return inputs[0];
104 }
105
SetClientVolume(float gain)106 bool HpaeGainNode::SetClientVolume(float gain)
107 {
108 preGain_ = curGain_;
109 curGain_ = gain;
110 isGainChanged_ = true;
111 return true;
112 }
113
GetClientVolume()114 float HpaeGainNode::GetClientVolume()
115 {
116 return curGain_;
117 }
118
SetFadeState(IOperation operation)119 void HpaeGainNode::SetFadeState(IOperation operation)
120 {
121 operation_ = operation;
122 // fade in
123 if (operation_ == OPERATION_STARTED) {
124 if (fadeInState_ == false) { // todo: add operation for softstart
125 fadeInState_ = true;
126 } else {
127 AUDIO_WARNING_LOG("fadeInState already set");
128 }
129 fadeOutState_ = FadeOutState::NO_FADEOUT; // reset fadeOutState_
130 }
131
132 // fade out
133 if (operation_ == OPERATION_PAUSED || operation_ == OPERATION_STOPPED) {
134 if (fadeOutState_ == FadeOutState::NO_FADEOUT) {
135 fadeOutState_ = FadeOutState::DO_FADEOUT;
136 } else {
137 AUDIO_WARNING_LOG("current fadeout state %{public}d, cannot prepare fadeout", fadeOutState_);
138 }
139 }
140 AUDIO_DEBUG_LOG("fadeInState_[%{public}d], fadeOutState_[%{public}d]", fadeInState_, fadeOutState_);
141 }
142
143
DoFading(HpaePcmBuffer * input)144 void HpaeGainNode::DoFading(HpaePcmBuffer *input)
145 {
146 if (!input->IsValid() && fadeOutState_ == FadeOutState::DO_FADEOUT) {
147 AUDIO_WARNING_LOG("after drain, get invalid data, no need to do fade out");
148 fadeOutState_ = FadeOutState::DONE_FADEOUT;
149 auto statusCallback = GetNodeStatusCallback().lock();
150 CHECK_AND_RETURN_LOG(statusCallback != nullptr, "statusCallback is null, cannot callback");
151 statusCallback->OnFadeDone(GetSessionId(), operation_);
152 return;
153 }
154 AudioRawFormat rawFormat;
155 rawFormat.format = SAMPLE_F32LE; // for now PCM in gain node is float32
156 rawFormat.channels = GetChannelCount();
157 uint32_t byteLength = 0;
158 uint8_t *data = (uint8_t *)input->GetPcmDataBuffer();
159 GetFadeLength(byteLength, input);
160 int32_t bufferAvg = GetSimpleBufferAvg(data, byteLength);
161 // do fade out
162 if (fadeOutState_ == FadeOutState::DO_FADEOUT) {
163 AUDIO_INFO_LOG("[%{public}d]: fade out started! buffer avg: %{public}d", GetSessionId(), bufferAvg);
164 ProcessVol(data, byteLength, rawFormat, FADE_HIGH, FADE_LOW);
165 fadeOutState_ = FadeOutState::DONE_FADEOUT;
166 AUDIO_INFO_LOG("fade out done, session %{public}d callback to update status", GetSessionId());
167 auto statusCallback = GetNodeStatusCallback().lock();
168 CHECK_AND_RETURN_LOG(statusCallback != nullptr, "statusCallback is null, cannot callback");
169 statusCallback->OnFadeDone(GetSessionId(), operation_); // if operation is stop or pause, callback
170 return;
171 }
172 // do fade in
173 if (fadeInState_) {
174 if (!input->IsValid() || IsSilentData(input)) {
175 AUDIO_DEBUG_LOG("[%{public}d]: silent or invalid data no need to do fade in", GetSessionId());
176 return;
177 }
178 AUDIO_INFO_LOG("[%{public}d]: fade in started! buffer avg: %{public}d", GetSessionId(), bufferAvg);
179 ProcessVol(data, byteLength, rawFormat, FADE_LOW, FADE_HIGH);
180 fadeInState_ = false;
181 }
182 }
183
SilenceData(HpaePcmBuffer * pcmBuffer)184 void HpaeGainNode::SilenceData(HpaePcmBuffer *pcmBuffer)
185 {
186 void *data = pcmBuffer->GetPcmDataBuffer();
187 if (GetNodeInfo().format == INVALID_WIDTH) {
188 AUDIO_WARNING_LOG("HpaePcmBuffer.SetDataSilence: invalid format");
189 } else if (GetNodeInfo().format == SAMPLE_U8) {
190 // set silence data for all the frames
191 memset_s(data, pcmBuffer->Size(), 0x80, pcmBuffer->Size());
192 } else {
193 memset_s(data, pcmBuffer->Size(), 0, pcmBuffer->Size());
194 }
195 }
196
DoGain(HpaePcmBuffer * input,uint32_t frameLen,uint32_t channelCount)197 void HpaeGainNode::DoGain(HpaePcmBuffer *input, uint32_t frameLen, uint32_t channelCount)
198 {
199 struct VolumeValues volumes;
200 float *inputData = (float *)input->GetPcmDataBuffer();
201 AudioVolume *audioVolume = AudioVolume::GetInstance();
202 float curSystemGain = 1.0f;
203 float preSystemGain = 1.0f;
204 if (isInnerCapturer_) {
205 curSystemGain = audioVolume->GetStreamVolume(GetSessionId());
206 preSystemGain = audioVolume->GetHistoryVolume(GetSessionId());
207 } else {
208 curSystemGain = audioVolume->GetVolume(GetSessionId(), GetStreamType(), GetDeviceClass(), &volumes);
209 preSystemGain = volumes.volumeHistory;
210 }
211 CHECK_AND_RETURN_LOG(frameLen != 0, "framelen is zero, invalid val.");
212 float systemStepGain = (curSystemGain - preSystemGain) / frameLen;
213 AUDIO_DEBUG_LOG(
214 "curSystemGain:%{public}f, preSystemGain:%{public}f, systemStepGain:%{public}f deviceClass :%{public}s",
215 curSystemGain,
216 preSystemGain,
217 systemStepGain,
218 GetDeviceClass().c_str());
219 if (audioVolume->IsSameVolume(0.0f, curSystemGain) && audioVolume->IsSameVolume(0.0f, preSystemGain)) {
220 SilenceData(input);
221 input->SetBufferSilence(true);
222 } else {
223 for (uint32_t i = 0; i < frameLen; i++) {
224 for (uint32_t j = 0; j < channelCount; j++) {
225 inputData[channelCount * i + j] =
226 inputData[channelCount * i + j] * (preSystemGain + systemStepGain * i);
227 }
228 }
229 input->SetBufferSilence(false);
230 }
231 if (fabs(curSystemGain - preSystemGain) > EPSILON) {
232 audioVolume->SetHistoryVolume(GetSessionId(), curSystemGain);
233 audioVolume->Monitor(GetSessionId(), true);
234 }
235 }
236
IsSilentData(HpaePcmBuffer * pcmBuffer)237 bool HpaeGainNode::IsSilentData(HpaePcmBuffer *pcmBuffer)
238 {
239 float *data = pcmBuffer->GetPcmDataBuffer();
240 size_t length = pcmBuffer->Size() / sizeof(float);
241 AUDIO_DEBUG_LOG("HpaeGainNode::Data length:%{public}zu", length);
242 return std::all_of(data, data + length, [](float value) {
243 return fabs(value) < EPSILON;
244 });
245 }
246
GetFadeLength(uint32_t & byteLength,HpaePcmBuffer * input)247 void HpaeGainNode::GetFadeLength(uint32_t &byteLength, HpaePcmBuffer *input)
248 {
249 uint32_t channels = GetChannelCount();
250 switch (GetNodeInfo().fadeType) {
251 case FadeType::SHORT_FADE: {
252 byteLength = static_cast<float>(GetSampleRate()) * SHORT_FADE_PERIOD * channels * sizeof(float);
253 AUDIO_DEBUG_LOG("GainNode: short fade length in Bytes: %{public}u", byteLength);
254 break;
255 }
256 case FadeType::DEFAULT_FADE: {
257 byteLength = input->DataSize();
258 AUDIO_DEBUG_LOG("GainNode: default fade length in Bytes: %{public}u", byteLength);
259 break;
260 }
261 default:
262 break;
263 }
264 }
265 } // namespace HPAE
266 } // namespace AudioStandard
267 } // namespace OHOS