1 /*
2 * Copyright (c) 2024-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 #undef LOG_TAG
17 #define LOG_TAG "OfflineAudioEffectServerChain"
18
19 #include "offline_audio_effect_server_chain.h"
20
21 #include <algorithm>
22 #include <chrono>
23 #include <cinttypes>
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <string>
28 #include <unistd.h>
29 #include "securec.h"
30
31 #include "audio_common_log.h"
32 #include "audio_errors.h"
33 #include "audio_utils.h"
34
35 using namespace OHOS::AudioStandard;
36
37 namespace OHOS {
38 namespace AudioStandard {
39 namespace {
40 constexpr uint32_t MAX_DESCRIPTOR_NUM = 20;
41 constexpr uint32_t MAX_CMD_LEN = 10;
42 constexpr uint32_t MAX_REPLY_LEN = 10;
43 constexpr uint32_t MAX_TIME_INTERVAL_MS = 160; // ms
44 // key for effectName, value for (libName, effectId)
45 static std::map<std::string, std::pair<std::string, std::string>> g_chainName2infoMap;
46 static std::mutex g_chainMutex;
47 }
48
49 template<typename T>
FreeIfNotNull(T * & ptr)50 static inline void FreeIfNotNull(T*& ptr)
51 {
52 if (ptr != nullptr) {
53 free(ptr);
54 ptr = nullptr;
55 }
56 }
57
GetByteSize(AudioSampleFormat format)58 static inline int32_t GetByteSize(AudioSampleFormat format)
59 {
60 static const std::unordered_map<AudioSampleFormat, int32_t> sizeMap = {
61 {SAMPLE_U8, 1},
62 {SAMPLE_S16LE, 2},
63 {SAMPLE_S24LE, 3},
64 {SAMPLE_S32LE, 4},
65 {SAMPLE_F32LE, 4}
66 };
67
68 auto it = sizeMap.find(format);
69 return (it != sizeMap.end()) ? it->second : 2; // Default size is 2
70 }
71
OfflineAudioEffectServerChain(const std::string & chainName)72 OfflineAudioEffectServerChain::OfflineAudioEffectServerChain(const std::string &chainName) : chainName_(chainName) {}
73
~OfflineAudioEffectServerChain()74 OfflineAudioEffectServerChain::~OfflineAudioEffectServerChain()
75 {
76 if (controller_) {
77 Release();
78 }
79 FreeIfNotNull(controllerId_.libName);
80 FreeIfNotNull(controllerId_.effectId);
81 serverBufferIn_ = nullptr;
82 serverBufferOut_ = nullptr;
83 DumpFileUtil::CloseDumpFile(&dumpFileIn_);
84 DumpFileUtil::CloseDumpFile(&dumpFileOut_);
85 }
86
InitEffectModel()87 static struct IEffectModel *InitEffectModel()
88 {
89 static struct IEffectModel *effectModel = IEffectModelGet(false);
90 return effectModel;
91 }
92
InitControllerDescriptor()93 static void InitControllerDescriptor()
94 {
95 std::lock_guard<std::mutex> maplock(g_chainMutex);
96 if (g_chainName2infoMap.size() > 0) {
97 return;
98 }
99 static uint32_t descsLen = MAX_DESCRIPTOR_NUM;
100 auto model = InitEffectModel();
101 CHECK_AND_RETURN_LOG(model, "get all descriptor failed, effectmodel is nullptr");
102 struct EffectControllerDescriptor descs[MAX_DESCRIPTOR_NUM];
103 int32_t ret = model->GetAllEffectDescriptors(model, descs, &descsLen);
104 CHECK_AND_RETURN_LOG(model, "get all descriptor failed, errCode is %{public}d", ret);
105 for (uint32_t i = 0; i < descsLen; i++) {
106 g_chainName2infoMap.insert_or_assign(descs[i].effectName,
107 std::make_pair(std::string(descs[i].libName), std::string(descs[i].effectId)));
108 FreeIfNotNull(descs[i].effectName);
109 FreeIfNotNull(descs[i].libName);
110 FreeIfNotNull(descs[i].effectId);
111 FreeIfNotNull(descs[i].supplier);
112 }
113 }
114
InitDump()115 void OfflineAudioEffectServerChain::InitDump()
116 {
117 static uint32_t chainId = 0;
118 std::string dumpFileName = "OfflineEffectServer";
119 std::string dumpFileInName = dumpFileName + "_" + std::to_string(chainId) + "_In.pcm";
120 std::string dumpFileOutName = dumpFileName + "_" + std::to_string(chainId) + "_Out.pcm";
121 DumpFileUtil::OpenDumpFile(DumpFileUtil::DUMP_SERVER_PARA, dumpFileInName, &dumpFileIn_);
122 DumpFileUtil::OpenDumpFile(DumpFileUtil::DUMP_SERVER_PARA, dumpFileOutName, &dumpFileOut_);
123 chainId++;
124 }
125
GetOfflineAudioEffectChains(std::vector<std::string> & chainNamesVector)126 int32_t OfflineAudioEffectServerChain::GetOfflineAudioEffectChains(std::vector<std::string> &chainNamesVector)
127 {
128 InitControllerDescriptor();
129 std::lock_guard<std::mutex> maplock(g_chainMutex);
130 for (auto item : g_chainName2infoMap) {
131 chainNamesVector.emplace_back(item.first);
132 AUDIO_DEBUG_LOG("effectName: %{public}s libName: %{public}s effectId: %{public}s", item.first.c_str(),
133 item.second.first.c_str(), item.second.second.c_str());
134 }
135 AUDIO_INFO_LOG("GetOfflineAudioEffectChains done");
136 return SUCCESS;
137 }
138
Create()139 int32_t OfflineAudioEffectServerChain::Create()
140 {
141 InitControllerDescriptor();
142 std::lock_guard<std::mutex> maplock(g_chainMutex);
143 auto mapIter = g_chainName2infoMap.find(chainName_);
144 CHECK_AND_RETURN_RET_LOG(mapIter != g_chainName2infoMap.end(), ERROR,
145 "create failed, no chain named %{public}s", chainName_.c_str());
146 auto model = InitEffectModel();
147 CHECK_AND_RETURN_RET_LOG(model, ERROR, "create failed, effectmodel is nullptr");
148
149 // second.first for libName, second.second for effectId, 1 for ioDirection
150 // do not need to release char* in info
151 struct EffectInfo info = {&mapIter->second.first[0], &mapIter->second.second[0], 1};
152
153 int32_t ret = model->CreateEffectController(model, &info, &controller_, &controllerId_);
154 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR,
155 "create %{public}s effect controller failed, errCode is %{public}d", chainName_.c_str(), ret);
156
157 int8_t input[MAX_CMD_LEN] = {0};
158 int8_t output[MAX_REPLY_LEN] = {0};
159 uint32_t replyLen = MAX_REPLY_LEN;
160
161 std::lock_guard<std::mutex> lock(offlineChainMutex_);
162 CHECK_AND_RETURN_RET_LOG(controller_, ERROR, "enable failed, controller is nullptr");
163 ret = controller_->SendCommand(controller_, AUDIO_EFFECT_COMMAND_ENABLE,
164 static_cast<int8_t *>(input), MAX_CMD_LEN, output, &replyLen);
165 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR,
166 "%{public}s effect COMMAND_ENABLE failed, errCode is %{public}d", chainName_.c_str(), ret);
167
168 InitDump();
169
170 AUDIO_INFO_LOG("Create %{public}s done", chainName_.c_str());
171 return SUCCESS;
172 }
173
SetParam(AudioStreamInfo inInfo,AudioStreamInfo outInfo)174 int32_t OfflineAudioEffectServerChain::SetParam(AudioStreamInfo inInfo, AudioStreamInfo outInfo)
175 {
176 AUDIO_INFO_LOG("%{public}d %{public}d %{public}hhu %{public}hhu %{public}" PRIu64 " InStreamInfo set",
177 inInfo.samplingRate, inInfo.encoding, inInfo.format, inInfo.channels, inInfo.channelLayout);
178 AUDIO_INFO_LOG("%{public}d %{public}d %{public}hhu %{public}hhu %{public}" PRIu64 " OutStreamInfo set",
179 outInfo.samplingRate, outInfo.encoding, outInfo.format, outInfo.channels, outInfo.channelLayout);
180
181 offlineConfig_.inputCfg = {inInfo.samplingRate, inInfo.channels, inInfo.format};
182 offlineConfig_.outputCfg = {outInfo.samplingRate, outInfo.channels, outInfo.format};
183
184 int8_t output[MAX_REPLY_LEN] = {0};
185 uint32_t replyLen = MAX_REPLY_LEN;
186
187 std::lock_guard<std::mutex> lock(offlineChainMutex_);
188 CHECK_AND_RETURN_RET_LOG(controller_, ERROR, "configure failed, controller is nullptr");
189 int32_t ret = controller_->SendCommand(controller_, AUDIO_EFFECT_COMMAND_SET_CONFIG,
190 reinterpret_cast<int8_t *>(&offlineConfig_), sizeof(offlineConfig_), output, &replyLen);
191 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR,
192 "%{public}s effect COMMAND_SET_CONFIG failed, errCode is %{public}d", chainName_.c_str(), ret);
193
194 inBufferSize_ = static_cast<uint32_t>(GetByteSize(inInfo.format)) * inInfo.samplingRate * inInfo.channels *
195 MAX_TIME_INTERVAL_MS / AUDIO_MS_PER_SECOND;
196 outBufferSize_ = static_cast<uint32_t>(GetByteSize(outInfo.format)) * outInfo.samplingRate * outInfo.channels *
197 MAX_TIME_INTERVAL_MS / AUDIO_MS_PER_SECOND;
198 return SUCCESS;
199 }
200
GetEffectBufferSize(uint32_t & inBufferSize,uint32_t & outBufferSize)201 int32_t OfflineAudioEffectServerChain::GetEffectBufferSize(uint32_t &inBufferSize, uint32_t &outBufferSize)
202 {
203 CHECK_AND_RETURN_RET_LOG(inBufferSize_ != 0, ERROR, "inBufferSize_ do not init");
204 CHECK_AND_RETURN_RET_LOG(outBufferSize_ != 0, ERROR, "inBufferSize_ do not init");
205 inBufferSize = inBufferSize_;
206 outBufferSize = outBufferSize_;
207 AUDIO_INFO_LOG("GetEffectBufferSize in server done, inBufferSize_:%{public}u inBufferSize_:%{public}u",
208 inBufferSize_, outBufferSize_);
209 return SUCCESS;
210 }
211
Prepare(const std::shared_ptr<AudioSharedMemory> & bufferIn,const std::shared_ptr<AudioSharedMemory> & bufferOut)212 int32_t OfflineAudioEffectServerChain::Prepare(const std::shared_ptr<AudioSharedMemory> &bufferIn,
213 const std::shared_ptr<AudioSharedMemory> &bufferOut)
214 {
215 serverBufferIn_ = bufferIn;
216 serverBufferOut_ = bufferOut;
217 AUDIO_INFO_LOG("Prepare in server done");
218 return SUCCESS;
219 }
220
Process(uint32_t inSize,uint32_t outSize)221 int32_t OfflineAudioEffectServerChain::Process(uint32_t inSize, uint32_t outSize)
222 {
223 CHECK_AND_RETURN_RET_LOG(serverBufferIn_ && serverBufferIn_->GetBase(), ERROR, "serverBufferIn_ is nullptr");
224 CHECK_AND_RETURN_RET_LOG(serverBufferOut_ && serverBufferOut_->GetBase(), ERROR, "serverBufferOut_ is nullptr");
225
226 CHECK_AND_RETURN_RET_LOG(inSize <= inBufferSize_, ERROR,
227 "inSize %{public}u > serverInBufferSize %{public}u", inSize, inBufferSize_);
228 CHECK_AND_RETURN_RET_LOG(outSize <= outBufferSize_, ERROR,
229 "outSize %{public}u > serverOutBufferSize %{public}u", outSize, outBufferSize_);
230
231 DumpFileUtil::WriteDumpFile(dumpFileIn_, serverBufferIn_->GetBase(), inSize);
232
233 struct AudioEffectBuffer input;
234 struct AudioEffectBuffer output;
235
236 input = {static_cast<int32_t>(inSize) / GetFormatByteSize(offlineConfig_.inputCfg.format),
237 GetFormatByteSize(offlineConfig_.inputCfg.format),
238 reinterpret_cast<int8_t *>(serverBufferIn_->GetBase()), static_cast<int32_t>(inSize)};
239 output = {};
240
241 std::lock_guard<std::mutex> lock(offlineChainMutex_);
242 CHECK_AND_RETURN_RET_LOG(controller_, ERROR, "process failed, controller is nullptr");
243 int32_t ret = controller_->EffectProcess(controller_, &input, &output);
244 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR, "EffectProcess failed ret:%{public}d", ret);
245 ret = memcpy_s(reinterpret_cast<int8_t *>(serverBufferOut_->GetBase()), outSize,
246 output.rawData, output.frameCount * GetFormatByteSize(offlineConfig_.outputCfg.format));
247 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR, "memcpy failed, ret:%{public}d", ret);
248 FreeIfNotNull(output.rawData);
249
250 DumpFileUtil::WriteDumpFile(dumpFileOut_, serverBufferOut_->GetBase(), outSize);
251 return SUCCESS;
252 }
253
Release()254 int32_t OfflineAudioEffectServerChain::Release()
255 {
256 auto model = InitEffectModel();
257 CHECK_AND_RETURN_RET_LOG(model, ERROR, "model is nullptr");
258
259 std::lock_guard<std::mutex> lock(offlineChainMutex_);
260 int32_t ret = model->DestroyEffectController(model, &controllerId_);
261 controller_ = nullptr;
262 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR,
263 "chainId:%{public}s release failed, errCode is %{public}d", controllerId_.effectId, ret);
264
265 AUDIO_INFO_LOG("Release in server success");
266 return SUCCESS;
267 }
268 } // namespace AudioStandard
269 } // namespace OHOS
270