• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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