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