1 /*
2 * Copyright (c) 2023 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 "AudioSpatialChannelConverter"
17 #endif
18
19 #include "audio_spatial_channel_converter.h"
20
21 #include <cstdint>
22 #include <string>
23 #include <iostream>
24 #include "media_monitor_manager.h"
25 #include "audio_utils.h"
26
27 namespace OHOS {
28 namespace AudioStandard {
29 static constexpr int32_t AUDIO_VIVID_SAMPLES = 1024;
30 static constexpr int32_t AVS3METADATA_SIZE = 19824;
31 static constexpr int32_t INVALID_FORMAT = -1;
32 static constexpr uint64_t DEFAULT_LAYOUT = CH_LAYOUT_UNKNOWN;
33
34 #if (defined(__aarch64__) || defined(__x86_64__))
35 constexpr const char *LD_EFFECT_LIBRARY_PATH[] = {"/system/lib64/"};
36 #else
37 constexpr const char *LD_EFFECT_LIBRARY_PATH[] = {"/system/lib/"};
38 #endif
39
40 static std::map<uint8_t, int8_t> format2bps = {
41 {SAMPLE_U8, sizeof(uint8_t)},
42 {SAMPLE_S16LE, sizeof(int16_t)},
43 {SAMPLE_S24LE, sizeof(int16_t) + sizeof(int8_t)},
44 {SAMPLE_S32LE, sizeof(int32_t)},
45 {SAMPLE_F32LE, sizeof(float)}};
46
GetBps(uint8_t format)47 static int8_t GetBps(uint8_t format)
48 {
49 return format2bps.count(format) > 0 ? format2bps[format] : INVALID_FORMAT;
50 }
51
GetPcmLength(int32_t channels,int8_t bps)52 size_t AudioSpatialChannelConverter::GetPcmLength(int32_t channels, int8_t bps)
53 {
54 if (encoding_ == ENCODING_AUDIOVIVID) {
55 return channels * AUDIO_VIVID_SAMPLES * bps;
56 }
57 AUDIO_INFO_LOG("encodingType is not supported."); // never run
58 return 0;
59 }
60
GetMetaSize()61 size_t AudioSpatialChannelConverter::GetMetaSize()
62 {
63 if (encoding_ == ENCODING_AUDIOVIVID) {
64 return AVS3METADATA_SIZE;
65 }
66 AUDIO_INFO_LOG("encodingType is not supported."); // never run
67 return 0;
68 }
69
Init(const AudioStreamParams info,const ConverterConfig cfg)70 bool AudioSpatialChannelConverter::Init(const AudioStreamParams info, const ConverterConfig cfg)
71 {
72 inChannel_ = info.channels;
73 outChannel_ = info.channels;
74
75 encoding_ = info.encoding;
76 sampleRate_ = info.samplingRate;
77
78 bps_ = GetBps(info.format);
79 CHECK_AND_RETURN_RET_LOG(bps_ > 0, false, "channel converter: Unsupported sample format");
80
81 Library library = cfg.library;
82 outChannelLayout_ = cfg.outChannelLayout;
83
84 loadSuccess_ = false;
85 if (externalLoader_.AddAlgoHandle(library)) {
86 outChannel_ = __builtin_popcountll(outChannelLayout_);
87 externalLoader_.SetIOBufferConfig(true, sampleRate_, info.format, inChannel_, info.channelLayout);
88 externalLoader_.SetIOBufferConfig(false, sampleRate_, info.format, outChannel_, outChannelLayout_);
89 if (externalLoader_.Init()) {
90 loadSuccess_ = true;
91 }
92 }
93 if (!loadSuccess_) {
94 outChannel_ = info.channels;
95 outChannelLayout_ = DEFAULT_LAYOUT; // can not convert
96 }
97 return true;
98 }
99
ConverterChannels(uint8_t & channels,uint64_t & channelLayout)100 void AudioSpatialChannelConverter::ConverterChannels(uint8_t &channels, uint64_t &channelLayout)
101 {
102 channels = outChannel_;
103 channelLayout = outChannelLayout_;
104 }
105
GetInputBufferSize(size_t & bufferSize)106 bool AudioSpatialChannelConverter::GetInputBufferSize(size_t &bufferSize)
107 {
108 bufferSize = GetPcmLength(inChannel_, bps_);
109 return bufferSize > 0;
110 }
111
CheckInputValid(const BufferDesc bufDesc)112 bool AudioSpatialChannelConverter::CheckInputValid(const BufferDesc bufDesc)
113 {
114 if (bufDesc.buffer == nullptr || bufDesc.metaBuffer == nullptr) {
115 AUDIO_ERR_LOG("pcm or metadata buffer is nullptr");
116 return false;
117 }
118 if (bufDesc.bufLength != GetPcmLength(inChannel_, bps_)) {
119 AUDIO_ERR_LOG("pcm bufLength invalid, pcmBufferSize = %{public}zu, excepted %{public}zu", bufDesc.bufLength,
120 GetPcmLength(inChannel_, bps_));
121 return false;
122 }
123 if (bufDesc.metaLength != GetMetaSize()) {
124 AUDIO_ERR_LOG("metadata bufLength invalid, metadataBufferSize = %{public}zu, excepted %{public}zu",
125 bufDesc.metaLength, GetMetaSize());
126 return false;
127 }
128 return true;
129 }
130
AllocateMem()131 bool AudioSpatialChannelConverter::AllocateMem()
132 {
133 outPcmBuf_ = std::make_unique<uint8_t[]>(GetPcmLength(outChannel_, bps_));
134 return outPcmBuf_ != nullptr;
135 }
136
GetOutputBufferStream(uint8_t * & buffer,uint32_t & bufferLen)137 void AudioSpatialChannelConverter::GetOutputBufferStream(uint8_t *&buffer, uint32_t &bufferLen)
138 {
139 buffer = outPcmBuf_.get();
140 bufferLen = static_cast<uint32_t>(GetPcmLength(outChannel_, bps_));
141 }
142
Process(const BufferDesc bufDesc)143 void AudioSpatialChannelConverter::Process(const BufferDesc bufDesc)
144 {
145 size_t n = GetPcmLength(outChannel_, bps_);
146 if (!loadSuccess_) {
147 std::copy(bufDesc.buffer, bufDesc.buffer + n, outPcmBuf_.get());
148 } else {
149 AudioBuffer inBuffer = {.frameLength = AUDIO_VIVID_SAMPLES,
150 .raw = bufDesc.buffer,
151 .metaData = bufDesc.metaBuffer};
152 AudioBuffer outBuffer = {.frameLength = AUDIO_VIVID_SAMPLES,
153 .raw = outPcmBuf_.get(),
154 .metaData = bufDesc.metaBuffer};
155 if (externalLoader_.ApplyAlgo(inBuffer, outBuffer) != 0) {
156 std::fill(outPcmBuf_.get(), outPcmBuf_.get() + n, 0);
157 }
158 }
159 }
160
Flush()161 bool AudioSpatialChannelConverter::Flush()
162 {
163 return loadSuccess_ ? externalLoader_.FlushAlgo() : true;
164 }
165
GetLatency()166 uint32_t AudioSpatialChannelConverter::GetLatency()
167 {
168 return loadSuccess_ ? externalLoader_.GetLatency() : 0;
169 }
170
ResolveLibrary(const std::string & path,std::string & resovledPath)171 static bool ResolveLibrary(const std::string &path, std::string &resovledPath)
172 {
173 for (auto *libDir : LD_EFFECT_LIBRARY_PATH) {
174 std::string candidatePath = std::string(libDir) + "/" + path;
175 if (access(candidatePath.c_str(), R_OK) == 0) {
176 resovledPath = std::move(candidatePath);
177 return true;
178 }
179 }
180 return false;
181 }
182
~LibLoader()183 LibLoader::~LibLoader()
184 {
185 if (libEntry_ != nullptr && libEntry_->audioEffectLibHandle != nullptr) {
186 libEntry_->audioEffectLibHandle->releaseEffect(handle_);
187 }
188 if (libHandle_ != nullptr) {
189 #ifndef TEST_COVERAGE
190 dlclose(libHandle_);
191 #endif
192 libHandle_ = nullptr;
193 }
194 }
195
LoadLibrary(const std::string & relativePath)196 bool LibLoader::LoadLibrary(const std::string &relativePath) noexcept
197 {
198 std::string absolutePath;
199 // find library in adsolutePath
200 bool ret = ResolveLibrary(relativePath, absolutePath);
201 CHECK_AND_RETURN_RET_LOG(ret, false, "<log error> find library falied in effect directories: %{public}s",
202 relativePath.c_str());
203
204 libHandle_ = dlopen(absolutePath.c_str(), 1);
205 CHECK_AND_RETURN_RET_LOG(libHandle_, false, "<log error> dlopen lib %{public}s Fail", relativePath.c_str());
206 AUDIO_INFO_LOG("<log info> dlopen lib %{public}s successful", relativePath.c_str());
207 dlerror(); // clear error, only need to check libHandle_ is not nullptr
208
209 AudioEffectLibrary *audioEffectLibHandle = static_cast<AudioEffectLibrary *>(dlsym(libHandle_,
210 AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR));
211 if (!audioEffectLibHandle) {
212 AUDIO_ERR_LOG("<log error> dlsym failed: error: %{public}s", dlerror());
213 #ifndef TEST_COVERAGE
214 dlclose(libHandle_);
215 #endif
216 return false;
217 }
218 AUDIO_INFO_LOG("<log info> dlsym lib %{public}s successful", relativePath.c_str());
219
220 libEntry_->audioEffectLibHandle = audioEffectLibHandle;
221
222 return true;
223 }
224
SetIOBufferConfig(bool isInput,uint32_t sampleRate,uint8_t format,uint32_t channels,uint64_t channelLayout)225 void LibLoader::SetIOBufferConfig(bool isInput, uint32_t sampleRate, uint8_t format, uint32_t channels,
226 uint64_t channelLayout)
227 {
228 AudioBufferConfig &target = isInput ? ioBufferConfig_.inputCfg : ioBufferConfig_.outputCfg;
229 target = {sampleRate, channels, format, channelLayout, ENCODING_AUDIOVIVID};
230 }
231
AddAlgoHandle(Library library)232 bool LibLoader::AddAlgoHandle(Library library)
233 {
234 AudioEffectDescriptor descriptor = {.libraryName = library.name, .effectName = library.name};
235 libEntry_ = std::make_unique<AudioEffectLibEntry>();
236 libEntry_->libraryName = library.name;
237 bool loadLibrarySuccess = LoadLibrary(library.path);
238 if (!loadLibrarySuccess) {
239 Trace trace("SYSEVENT FAULT EVENT LOAD_EFFECT_ENGINE_ERROR, ENGINE_TYPE: "
240 + std::to_string(Media::MediaMonitor::AUDIO_CONVERTER_ENGINE));
241 // hisysevent for load engine error
242 std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
243 Media::MediaMonitor::AUDIO, Media::MediaMonitor::LOAD_EFFECT_ENGINE_ERROR,
244 Media::MediaMonitor::FAULT_EVENT);
245 bean->Add("ENGINE_TYPE", Media::MediaMonitor::AUDIO_CONVERTER_ENGINE);
246 Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
247
248 AUDIO_ERR_LOG("loadLibrary fail, please check logs!");
249 return false;
250 }
251
252 int32_t ret = libEntry_->audioEffectLibHandle->createEffect(descriptor, &handle_);
253 CHECK_AND_RETURN_RET_LOG(ret == 0, false, "%{public}s create fail", library.name.c_str());
254 return true;
255 }
256
Init()257 bool LibLoader::Init()
258 {
259 int32_t ret = 0;
260 uint32_t replyData = 0;
261 AudioEffectTransInfo cmdInfo = {sizeof(AudioEffectConfig), &ioBufferConfig_};
262 AudioEffectTransInfo replyInfo = {sizeof(int32_t), &replyData};
263 ret = (*handle_)->command(handle_, EFFECT_CMD_INIT, &cmdInfo, &replyInfo);
264 CHECK_AND_RETURN_RET_LOG(ret == 0, false, "[%{public}s] lib EFFECT_CMD_INIT fail", libEntry_->libraryName.c_str());
265 ret = (*handle_)->command(handle_, EFFECT_CMD_ENABLE, &cmdInfo, &replyInfo);
266 CHECK_AND_RETURN_RET_LOG(ret == 0, false, "[%{public}s] lib EFFECT_CMD_ENABLE fail",
267 libEntry_->libraryName.c_str());
268 ret = (*handle_)->command(handle_, EFFECT_CMD_SET_CONFIG, &cmdInfo, &replyInfo);
269 CHECK_AND_RETURN_RET_LOG(ret == 0, false, "[%{public}s] lib EFFECT_CMD_SET_CONFIG fail",
270 libEntry_->libraryName.c_str());
271 latency_ = replyData;
272 AUDIO_INFO_LOG("The delay of [%{public}s] lib is %{public}u", libEntry_->libraryName.c_str(), latency_);
273 return true;
274 }
275
GetLatency()276 uint32_t LibLoader::GetLatency()
277 {
278 return latency_;
279 }
280
ApplyAlgo(AudioBuffer & inputBuffer,AudioBuffer & outputBuffer)281 int32_t LibLoader::ApplyAlgo(AudioBuffer &inputBuffer, AudioBuffer &outputBuffer)
282 {
283 int32_t ret = (*handle_)->process(handle_, &inputBuffer, &outputBuffer);
284 CHECK_AND_RETURN_RET_LOG(ret == 0, ret, "converter algo lib process fail");
285 return ret;
286 }
287
FlushAlgo()288 bool LibLoader::FlushAlgo()
289 {
290 int32_t ret = 0;
291 int32_t replyData = 0;
292 AudioEffectTransInfo cmdInfo = {sizeof(AudioEffectConfig), &ioBufferConfig_};
293 AudioEffectTransInfo replyInfo = {sizeof(int32_t), &replyData};
294 ret = (*handle_)->command(handle_, EFFECT_CMD_ENABLE, &cmdInfo, &replyInfo);
295 CHECK_AND_RETURN_RET_LOG(ret == 0, false, "[%{public}s] lib EFFECT_CMD_ENABLE fail",
296 libEntry_->libraryName.c_str());
297 return true;
298 }
299 } // namespace AudioStandard
300 } // namespace OHOS