• 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 "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