• 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 #ifndef LOG_TAG
16 #define LOG_TAG "HpaeLoudnessGainNode"
17 #endif
18 
19 #include <dlfcn.h>
20 #include <cinttypes>
21 #include <cmath>
22 #include "hpae_loudness_gain_node.h"
23 #include "hpae_pcm_buffer.h"
24 #include "audio_utils.h"
25 #include "audio_errors.h"
26 #include "audio_effect_log.h"
27 
28 namespace OHOS {
29 namespace AudioStandard {
30 namespace HPAE {
31 static const std::string LOUDNESSGAIN_PATH = "/system/lib64/libaudio_integration_loudness.z.so";
32 static constexpr float EPSILON = 1e-6f;
33 static constexpr uint32_t SAMPLE_RATE = 48000;
34 static constexpr float DB_TO_AMPLITUDE_BASE = 10.0f;
35 static constexpr float DB_TO_AMPLITUDE_DIVISOR = 20.0f;
36 static const AudioEffectDescriptor LOUDNESS_DESCRIPTOR = {
37     .libraryName = "loudness",
38     .effectName = "loudness",
39 };
40 
IsFloatValueEqual(float a,float b)41 static inline bool IsFloatValueEqual(float a, float b)
42 {
43     return std::abs(a - b) < EPSILON;
44 }
45 
LoudnessDbToLinearGain(float loudnessGainDb)46 static inline float LoudnessDbToLinearGain(float loudnessGainDb)
47 {
48     return std::pow(DB_TO_AMPLITUDE_BASE, loudnessGainDb / DB_TO_AMPLITUDE_DIVISOR);
49 }
50 
HpaeLoudnessGainNode(HpaeNodeInfo & nodeInfo)51 HpaeLoudnessGainNode::HpaeLoudnessGainNode(HpaeNodeInfo &nodeInfo) : HpaeNode(nodeInfo), HpaePluginNode(nodeInfo),
52     pcmBufferInfo_(nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate, nodeInfo.channelLayout),
53     loudnessGainOutput_(pcmBufferInfo_)
54 {
55     AUDIO_INFO_LOG("HpaeLoudnessGainNode created");
56     dlHandle_ = dlopen(LOUDNESSGAIN_PATH.c_str(), 1);
57     if (!dlHandle_) {
58         AUDIO_ERR_LOG("<log error> dlopen lib %{public}s Fail", LOUDNESSGAIN_PATH.c_str());
59     } else {
60         AUDIO_INFO_LOG("<log info> dlopen lib %{public}s successful", LOUDNESSGAIN_PATH.c_str());
61     }
62     dlerror();
63 
64     audioEffectLibHandle_ = static_cast<AudioEffectLibrary *>(dlsym(dlHandle_,
65         AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR));
66     if (!audioEffectLibHandle_) {
67         AUDIO_ERR_LOG("<log error> dlsym failed: error: %{public}s", dlerror());
68         dlclose(dlHandle_);
69         dlHandle_ = nullptr;
70     }
71     AUDIO_INFO_LOG("<log info> dlsym lib %{public}s successful", LOUDNESSGAIN_PATH.c_str());
72 
73 #ifdef ENABLE_HIDUMP_DFX
74     SetNodeName("hpaeLoudnessGainNode");
75 #endif
76 }
77 
~HpaeLoudnessGainNode()78 HpaeLoudnessGainNode::~HpaeLoudnessGainNode()
79 {
80     if (handle_ && audioEffectLibHandle_) {
81         audioEffectLibHandle_->releaseEffect(handle_);
82         handle_ = nullptr;
83     }
84     if (dlHandle_) {
85         dlclose(dlHandle_);
86         dlHandle_ = nullptr;
87         audioEffectLibHandle_ = nullptr;
88     }
89 #ifdef ENABLE_HIDUMP_DFX
90     AUDIO_INFO_LOG("NodeId: %{public}u NodeName: %{public}s destructed.",
91         GetNodeId(), GetNodeName().c_str());
92 #endif
93 }
94 
SignalProcess(const std::vector<HpaePcmBuffer * > & inputs)95 HpaePcmBuffer *HpaeLoudnessGainNode::SignalProcess(const std::vector<HpaePcmBuffer *> &inputs)
96 {
97     Trace trace("HpaeLoudnessGainNode::SignalProcess");
98 
99     CHECK_AND_RETURN_RET_LOG((!inputs.empty()) && inputs[0], &silenceData_,
100         "NodeId %{public}d, sessionId %{public}d input is empty", GetNodeId(), GetSessionId());
101 
102     CHECK_AND_RETURN_RET((!IsFloatValueEqual(loudnessGain_, 0.0f)), inputs[0]);
103     CheckUpdateInfo(inputs[0]);
104     if (!dlHandle_ || !audioEffectLibHandle_) {
105         float *pcmDataBuffer = inputs[0]->GetPcmDataBuffer();
106         uint32_t bufferSize = inputs[0]->GetFrameLen() * inputs[0]->GetChannelCount();
107         float *dataBuffer = loudnessGainOutput_.GetPcmDataBuffer();
108         for (uint32_t i = 0; i < bufferSize; i++) {
109             dataBuffer[i] = pcmDataBuffer[i] * linearGain_;
110         }
111     } else {
112         AudioBuffer inBuffer = {
113             .frameLength = inputs[0]->GetFrameLen(),
114             .raw = inputs[0]->GetPcmDataBuffer(),
115             .metaData = nullptr
116         };
117         AudioBuffer outBuffer = {
118             .frameLength = inputs[0]->GetFrameLen(),
119             .raw = loudnessGainOutput_.GetPcmDataBuffer(),
120             .metaData = nullptr
121         };
122         CHECK_AND_RETURN_RET(handle_, inputs[0]);
123         int32_t ret = (*handle_)->process(handle_, &inBuffer, &outBuffer);
124         CHECK_AND_RETURN_RET_LOG(ret == 0, inputs[0], "loudness algo lib process failed");
125     }
126 
127     loudnessGainOutput_.SetBufferState(inputs[0]->GetBufferState());
128     return &loudnessGainOutput_;
129 }
130 
CheckUpdateInfo(HpaePcmBuffer * input)131 void HpaeLoudnessGainNode::CheckUpdateInfo(HpaePcmBuffer *input)
132 {
133     CHECK_AND_RETURN(pcmBufferInfo_.ch != input->GetChannelCount() ||
134         pcmBufferInfo_.frameLen != input->GetFrameLen() ||
135         pcmBufferInfo_.rate != input->GetSampleRate() ||
136         pcmBufferInfo_.channelLayout != input->GetChannelLayout());
137     AUDIO_INFO_LOG("Update pcmBufferInfo_: channel count: %{public}u -> %{public}u, frame len: %{public}u -> "
138         "%{public}u, sample rate: %{public}u -> %{public}u, channel layout: %{public}" PRIu64 " -> %{public}" PRIu64,
139         pcmBufferInfo_.ch, input->GetChannelCount(), pcmBufferInfo_.frameLen, input->GetFrameLen(),
140         pcmBufferInfo_.rate, input->GetSampleRate(), pcmBufferInfo_.channelLayout, input->GetChannelLayout());
141     pcmBufferInfo_.ch = input->GetChannelCount();
142     pcmBufferInfo_.frameLen = input->GetFrameLen();
143     pcmBufferInfo_.rate = input->GetSampleRate();
144     pcmBufferInfo_.channelLayout = input->GetChannelLayout();
145 
146     loudnessGainOutput_.ReConfig(pcmBufferInfo_);
147     silenceData_.ReConfig(pcmBufferInfo_);
148     silenceData_.SetBufferSilence(true);
149     CHECK_AND_RETURN_LOG(handle_, "no handle.");
150 
151     uint32_t replyData = 0;
152     AudioEffectConfig ioBufferConfig;
153     AudioEffectTransInfo replyInfo = {sizeof(int32_t), &replyData};
154     AudioEffectTransInfo cmdInfo = {sizeof(AudioEffectConfig), &ioBufferConfig};
155     ioBufferConfig.inputCfg = {SAMPLE_RATE, pcmBufferInfo_.ch, DATA_FORMAT_F32, pcmBufferInfo_.channelLayout,
156         ENCODING_PCM};
157     ioBufferConfig.outputCfg = ioBufferConfig.inputCfg;
158     int32_t ret = (*handle_)->command(handle_, EFFECT_CMD_SET_CONFIG, &cmdInfo, &replyInfo);
159     CHECK_AND_RETURN_LOG(ret == 0, "Loudness algo lib EFFECT_CMD_SET_CONFIG failed");
160 }
161 
ReleaseHandle(float loudnessGain)162 int32_t HpaeLoudnessGainNode::ReleaseHandle(float loudnessGain)
163 {
164     AUDIO_INFO_LOG("Releasing handle...");
165     CHECK_AND_RETURN_RET_LOG(handle_, ERROR, "no handle.");
166     int32_t ret = audioEffectLibHandle_->releaseEffect(handle_);
167     CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "handle releasing failed.");
168     handle_ = nullptr;
169     loudnessGain_ = loudnessGain;
170     return SUCCESS;
171 }
172 
SetLoudnessGain(float loudnessGain)173 int32_t HpaeLoudnessGainNode::SetLoudnessGain(float loudnessGain)
174 {
175     CHECK_AND_RETURN_RET_LOG(!IsFloatValueEqual(loudnessGain_, loudnessGain), SUCCESS,
176         "SetLoudnessGain: Same loudnessGain: %{public}f", loudnessGain);
177     AUDIO_INFO_LOG("loudnessGain changed from %{public}f to %{public}f", loudnessGain_, loudnessGain);
178     if (!dlHandle_ || !audioEffectLibHandle_) {
179         linearGain_ = LoudnessDbToLinearGain(loudnessGain);
180         loudnessGain_ = loudnessGain;
181         return SUCCESS;
182     }
183 
184     if (IsFloatValueEqual(loudnessGain, 0.0f)) {
185         return ReleaseHandle(loudnessGain);
186     }
187 
188     uint32_t replyData = 0;
189     AudioEffectTransInfo replyInfo = {sizeof(int32_t), &replyData};
190 
191     if (IsFloatValueEqual(loudnessGain_, 0.0f)) {
192         AUDIO_INFO_LOG("Creating handle...");
193         int32_t ret = audioEffectLibHandle_->createEffect(LOUDNESS_DESCRIPTOR, &handle_);
194         CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "loudness lib handle create failed");
195         AudioEffectConfig ioBufferConfig;
196         AudioEffectTransInfo cmdInfo = {sizeof(AudioEffectConfig), &ioBufferConfig};
197         ioBufferConfig.inputCfg = {SAMPLE_RATE, pcmBufferInfo_.ch, DATA_FORMAT_F32, pcmBufferInfo_.channelLayout,
198             ENCODING_PCM};
199         ioBufferConfig.outputCfg = ioBufferConfig.inputCfg;
200         ret = (*handle_)->command(handle_, EFFECT_CMD_INIT, &cmdInfo, &replyInfo);
201         CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "Loudness algo lib EFFECT_CMD_INIT failed");
202         ret = (*handle_)->command(handle_, EFFECT_CMD_ENABLE, &cmdInfo, &replyInfo);
203         CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "Loudness algo lib EFFECT_CMD_ENABLE failed");
204         ret = (*handle_)->command(handle_, EFFECT_CMD_SET_CONFIG, &cmdInfo, &replyInfo);
205         CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "Loudness algo lib EFFECT_CMD_SET_CONFIG failed");
206     }
207     std::vector<uint8_t> paramBuffer(sizeof(AudioEffectParam) + MAX_PARAM_INDEX * sizeof(int32_t));
208     AudioEffectParam *effectParam = reinterpret_cast<AudioEffectParam*>(paramBuffer.data());
209     effectParam->status = 0;
210     effectParam->paramSize = sizeof(int32_t);
211     effectParam->valueSize = 0;
212     int32_t *data = &(effectParam->data[0]);
213     data[COMMAND_CODE_INDEX] = EFFECT_SET_PARAM;
214     CHECK_AND_RETURN_RET_LOG(memcpy_s(&data[LOUDNESS_GAIN_INDEX], sizeof(float), &loudnessGain, sizeof(float)) == 0,
215         ERROR, "memcpy failed");
216 
217     AudioEffectTransInfo cmdInfo = {sizeof(AudioEffectParam) + sizeof(int32_t) * MAX_PARAM_INDEX, effectParam};
218     int32_t ret = (*handle_)->command(handle_, EFFECT_CMD_SET_PARAM, &cmdInfo, &replyInfo);
219     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR, "Loudness algo lib EFFECT_CMD_SET_PARAM failed");
220     loudnessGain_ = loudnessGain;
221 
222     return SUCCESS;
223 }
224 
GetLoudnessGain()225 float HpaeLoudnessGainNode::GetLoudnessGain()
226 {
227     return loudnessGain_;
228 }
229 
IsLoudnessAlgoOn()230 bool HpaeLoudnessGainNode::IsLoudnessAlgoOn()
231 {
232     return handle_ != nullptr;
233 }
234 
235 }  // namespace HPAE
236 }  // namespace AudioStandard
237 }  // namespace OHOS