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 "HpaeResampleNode"
18 #endif
19
20 #include <iostream>
21 #include <algorithm>
22 #include <memory>
23 #include "hpae_resample_node.h"
24 #include "hpae_pcm_buffer.h"
25 #include "audio_utils.h"
26 #include "audio_effect_log.h"
27
28 namespace OHOS {
29 namespace AudioStandard {
30 namespace HPAE {
31 constexpr int REASAMPLE_QUAILTY = 5;
Min(const uint32_t a,const uint32_t b)32 static inline uint32_t Min(const uint32_t a, const uint32_t b) {return a > b ? b : a;}
HpaeResampleNode(HpaeNodeInfo & preNodeInfo,HpaeNodeInfo & nodeInfo,ResamplerType type)33 HpaeResampleNode::HpaeResampleNode(HpaeNodeInfo &preNodeInfo, HpaeNodeInfo &nodeInfo, ResamplerType type)
34 : HpaeNode(nodeInfo), HpaePluginNode(nodeInfo),
35 pcmBufferInfo_(nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate),
36 resampleOutput_(pcmBufferInfo_), preNodeInfo_(preNodeInfo), tempOutput_(preNodeInfo.channels * nodeInfo.frameLen)
37 {
38 if (type == ResamplerType::PRORESAMPLER) {
39 resampler_ = std::make_unique<ProResampler>(preNodeInfo_.samplingRate, nodeInfo.samplingRate,
40 preNodeInfo_.channels, REASAMPLE_QUAILTY);
41 }
42 #ifdef ENABLE_HOOK_PCM
43 inputPcmDumper_ = std::make_unique<HpaePcmDumper>("HpaeResampleNodeInput1_id_" +
44 std::to_string(GetSessionId()) + "_ch_" + std::to_string(preNodeInfo_.channels) +
45 "_rate_" + std::to_string(preNodeInfo_.samplingRate) + "_scene_" +
46 std::to_string(HpaeNode::GetSceneType()) + "_" + GetTime() + ".pcm");
47 outputPcmDumper_ = std::make_unique<HpaePcmDumper>("HpaeResampleNodeOutput1_id_" +
48 std::to_string(GetSessionId()) + "_ch_" + std::to_string(GetChannelCount()) +
49 "_rate_" + std::to_string(GetSampleRate()) + "_scene_" +
50 std::to_string(HpaeNode::GetSceneType())+ "_" + GetTime() + ".pcm");
51 #endif
52 }
53
HpaeResampleNode(HpaeNodeInfo & preNodeInfo,HpaeNodeInfo & nodeInfo)54 HpaeResampleNode::HpaeResampleNode(HpaeNodeInfo &preNodeInfo, HpaeNodeInfo &nodeInfo)
55 : HpaeNode(nodeInfo), HpaePluginNode(nodeInfo),
56 pcmBufferInfo_(nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate),
57 resampleOutput_(pcmBufferInfo_), preNodeInfo_(preNodeInfo), tempOutput_(preNodeInfo.channels * nodeInfo.frameLen)
58 { // use ProResampler as default
59 resampler_ = std::make_unique<ProResampler>(preNodeInfo_.samplingRate, nodeInfo.samplingRate,
60 preNodeInfo_.channels, REASAMPLE_QUAILTY);
61
62 #ifdef ENABLE_HOOK_PCM
63 inputPcmDumper_ = std::make_unique<HpaePcmDumper>("HpaeResampleNodeInput1_id_" +
64 std::to_string(HpaeNode::GetSessionId()) + "_ch_" + std::to_string(preNodeInfo_.channels) + "_rate_" +
65 std::to_string(preNodeInfo_.samplingRate) + "_scene_" + std::to_string(HpaeNode::GetSceneType())+".pcm");
66
67 outputPcmDumper_ = std::make_unique<HpaePcmDumper>("HpaeResampleNodeOutput1_id_" +
68 std::to_string(HpaeNode::GetSessionId()) + "_ch_" + std::to_string(HpaeNode::GetChannelCount()) +
69 "_rate_" + std::to_string(HpaeNode::GetSampleRate()) +
70 "_scene_"+ std::to_string(HpaeNode::GetSceneType())+".pcm");
71 #endif
72 AUDIO_INFO_LOG("input rate %{public}u, output rate %{public}u", preNodeInfo_.samplingRate, nodeInfo.samplingRate);
73 AUDIO_INFO_LOG("input SessionId %{public}u, output streamType %{public}u", HpaeNode::GetSessionId(),
74 nodeInfo.streamType);
75 AUDIO_INFO_LOG("input ch %{public}u, output ch %{public}u", preNodeInfo_.channels, HpaeNode::GetChannelCount());
76 }
77
Reset()78 bool HpaeResampleNode::Reset()
79 {
80 if (resampler_ == nullptr) {
81 AUDIO_WARNING_LOG("resampler_ is nullptr, SessionId:%{public}d", GetSessionId());
82 return false;
83 }
84 resampler_->Reset();
85 return true;
86 }
87
SignalProcess(const std::vector<HpaePcmBuffer * > & inputs)88 HpaePcmBuffer *HpaeResampleNode::SignalProcess(const std::vector<HpaePcmBuffer *> &inputs)
89 {
90 Trace trace("[" + std::to_string(GetSessionId()) + "]HpaeResampleNode::SignalProcess");
91 if (inputs.empty()) {
92 AUDIO_WARNING_LOG("HpaeResampleNode inputs size is empty, SessionId:%{public}d", GetSessionId());
93 return nullptr;
94 }
95 if (inputs.size() != 1) {
96 AUDIO_WARNING_LOG("error inputs size is not eqaul to 1, SessionId:%{public}d", GetSessionId());
97 }
98 if (resampler_ == nullptr) {
99 return &silenceData_;
100 }
101 resampleOutput_.Reset();
102 uint32_t inputFrameLen = preNodeInfo_.frameLen;
103 uint32_t outputFrameLen = GetFrameLen();
104 float *srcData = (*(inputs[0])).GetPcmDataBuffer();
105 float *dstData = tempOutput_.data();
106 if (preNodeInfo_.channels == GetChannelCount()) {
107 dstData = resampleOutput_.GetPcmDataBuffer();
108 }
109 #ifdef ENABLE_HOOK_PCM
110 if (inputPcmDumper_ != nullptr) {
111 inputPcmDumper_->CheckAndReopenHandle();
112 inputPcmDumper_->Dump((int8_t *)(srcData), (inputFrameLen * sizeof(float) * preNodeInfo_.channels));
113 }
114 #endif
115 ResampleProcess(srcData, inputFrameLen, dstData, outputFrameLen);
116 return &resampleOutput_;
117 }
118
ResampleProcess(float * srcData,uint32_t inputFrameLen,float * dstData,uint32_t outputFrameLen)119 void HpaeResampleNode::ResampleProcess(float *srcData, uint32_t inputFrameLen, float *dstData, uint32_t outputFrameLen)
120 {
121 resampler_->Process(srcData, inputFrameLen, dstData, outputFrameLen);
122
123 if (preNodeInfo_.channels == GetChannelCount()) {
124 #ifdef ENABLE_HOOK_PCM
125 if (outputPcmDumper_ != nullptr) {
126 outputPcmDumper_->CheckAndReopenHandle();
127 outputPcmDumper_->Dump(
128 (int8_t *)(resampleOutput_.GetPcmDataBuffer()), GetFrameLen() * sizeof(float) * GetChannelCount());
129 }
130 #endif
131 return;
132 }
133
134 float *targetData = resampleOutput_.GetPcmDataBuffer();
135 uint32_t targetChannels = GetChannelCount();
136 for (uint32_t i = 0; i < outputFrameLen; ++i) {
137 for (uint32_t ch = 0; ch < targetChannels; ++ch) {
138 uint32_t leftChIndex = Min(ch, (preNodeInfo_.channels - 1));
139 targetData[i * targetChannels + ch] =
140 dstData[i * preNodeInfo_.channels + leftChIndex];
141 }
142 }
143
144 #ifdef ENABLE_HOOK_PCM
145 if (outputPcmDumper_ != nullptr) {
146 outputPcmDumper_->CheckAndReopenHandle();
147 outputPcmDumper_->Dump(
148 (int8_t *)(resampleOutput_.GetPcmDataBuffer()), GetFrameLen() * sizeof(float) * GetChannelCount());
149 }
150 #endif
151 }
152
ConnectWithInfo(const std::shared_ptr<OutputNode<HpaePcmBuffer * >> & preNode,HpaeNodeInfo & nodeInfo)153 void HpaeResampleNode::ConnectWithInfo(const std::shared_ptr<OutputNode<HpaePcmBuffer*>> &preNode,
154 HpaeNodeInfo &nodeInfo)
155 {
156 inputStream_.Connect(preNode->GetSharedInstance(), preNode->GetOutputPort(nodeInfo));
157 resampleOutput_.SetSourceBufferType(preNode->GetOutputPortBufferType(nodeInfo));
158 }
159
DisConnectWithInfo(const std::shared_ptr<OutputNode<HpaePcmBuffer * >> & preNode,HpaeNodeInfo & nodeInfo)160 void HpaeResampleNode::DisConnectWithInfo(const std::shared_ptr<OutputNode<HpaePcmBuffer*>> &preNode,
161 HpaeNodeInfo &nodeInfo)
162 {
163 inputStream_.DisConnect(preNode->GetOutputPort(nodeInfo, true));
164 }
165
166 } // namespace HPAE
167 } // namespace AudioStandard
168 } // namespace OHOS