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