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