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