• 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 #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