1 /*
2  * Copyright (c) 2022-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 
16 #include "daudio_utils.h"
17 
18 #include <ctime>
19 #include <map>
20 #include <ostream>
21 #include <sstream>
22 
23 #include "daudio_constants.h"
24 #include "daudio_errcode.h"
25 #include "daudio_log.h"
26 #include "parameter.h"
27 
28 #undef DH_LOG_TAG
29 #define DH_LOG_TAG "DAudioUtils"
30 
31 namespace OHOS {
32 namespace DistributedHardware {
33 constexpr size_t INT32_SHORT_ID_LENGTH = 20;
34 constexpr size_t INT32_PLAINTEXT_LENGTH = 4;
35 constexpr size_t INT32_MIN_ID_LENGTH = 3;
36 constexpr uint8_t MAX_KEY_DH_ID_LEN = 20;
37 
GetAnonyString(const std::string &value)38 std::string GetAnonyString(const std::string &value)
39 {
40     std::string res;
41     std::string tmpStr("******");
42     size_t strLen = value.length();
43     if (strLen < INT32_MIN_ID_LENGTH) {
44         return tmpStr;
45     }
46 
47     if (strLen <= INT32_SHORT_ID_LENGTH) {
48         res += value[0];
49         res += tmpStr;
50         res += value[strLen - 1];
51     } else {
52         res.append(value, 0, INT32_PLAINTEXT_LENGTH);
53         res += tmpStr;
54         res.append(value, strLen - INT32_PLAINTEXT_LENGTH, INT32_PLAINTEXT_LENGTH);
55     }
56 
57     return res;
58 }
59 
GetChangeDevIdMap(int32_t devId)60 std::string GetChangeDevIdMap(int32_t devId)
61 {
62     std::string result = PRINT_NONE;
63     switch (devId) {
64         case DEFAULT_CAPTURE_ID:
65             result = PRINT_MIC;
66             break;
67         case LOW_LATENCY_RENDER_ID:
68             result = PRINT_SPK;
69             break;
70         case DEFAULT_RENDER_ID:
71             result = PRINT_SPK;
72             break;
73         default:
74             break;
75     }
76     return result;
77 }
78 
GetAudioParamStr(const std::string &params, const std::string &key, std::string &value)79 int32_t GetAudioParamStr(const std::string &params, const std::string &key, std::string &value)
80 {
81     size_t step = key.size();
82     if (step >= params.size()) {
83         return ERR_DH_AUDIO_HDF_FAIL;
84     }
85     size_t pos = params.find(key);
86     if (pos == params.npos || params.at(pos + step) != '=') {
87         return ERR_DH_AUDIO_COMMON_NOT_FOUND_KEY;
88     }
89     size_t splitPosEnd = params.find(';', pos);
90     if (splitPosEnd != params.npos) {
91         if (pos + step + 1 > splitPosEnd) {
92             return ERR_DH_AUDIO_HDF_FAIL;
93         }
94         value = params.substr(pos + step + 1, splitPosEnd - pos - step - 1);
95     } else {
96         value = params.substr(pos + step + 1);
97     }
98     return DH_SUCCESS;
99 }
100 
GetAudioParamInt(const std::string &params, const std::string &key, int32_t &value)101 int32_t GetAudioParamInt(const std::string &params, const std::string &key, int32_t &value)
102 {
103     std::string val = "-1";
104     int32_t ret = GetAudioParamStr(params, key, val);
105     if (!CheckIsNum(val)) {
106         DHLOGE("String is not number. str:%{public}s.", val.c_str());
107         return -1;
108     }
109     value = std::atoi(val.c_str());
110     return ret;
111 }
112 
CheckIsNum(const std::string &jsonString)113 bool CheckIsNum(const std::string &jsonString)
114 {
115     if (jsonString.empty() || jsonString.size() > MAX_KEY_DH_ID_LEN) {
116         DHLOGE("Json string size is zero or too long.");
117         return false;
118     }
119     for (char const &c : jsonString) {
120         if (!std::isdigit(c)) {
121             DHLOGE("Json string is not number.");
122             return false;
123         }
124     }
125     return true;
126 }
127 
GetAudioParamUInt(const std::string &params, const std::string &key, uint32_t &value)128 int32_t GetAudioParamUInt(const std::string &params, const std::string &key, uint32_t &value)
129 {
130     value = 0;
131     return DH_SUCCESS;
132 }
133 
GetAudioParamBool(const std::string &params, const std::string &key, bool &value)134 int32_t GetAudioParamBool(const std::string &params, const std::string &key, bool &value)
135 {
136     std::string val;
137     GetAudioParamStr(params, key, val);
138     value = (val != "0");
139     return DH_SUCCESS;
140 }
141 
SetAudioParamStr(std::string &params, const std::string &key, const std::string &value)142 int32_t SetAudioParamStr(std::string &params, const std::string &key, const std::string &value)
143 {
144     params = params + key + '=' + value + ';';
145     return DH_SUCCESS;
146 }
147 
GetDevTypeByDHId(int32_t dhId)148 int32_t GetDevTypeByDHId(int32_t dhId)
149 {
150     if (static_cast<uint32_t>(dhId) & 0x8000000) {
151         return AUDIO_DEVICE_TYPE_MIC;
152     } else if (static_cast<uint32_t>(dhId) & 0x7ffffff) {
153         return AUDIO_DEVICE_TYPE_SPEAKER;
154     }
155     return AUDIO_DEVICE_TYPE_UNKNOWN;
156 }
157 
GetNowTimeUs()158 int64_t GetNowTimeUs()
159 {
160     std::chrono::microseconds nowUs =
161         std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
162     return nowUs.count();
163 }
164 
CalculateFrameSize(uint32_t sampleRate, uint32_t channelCount, int32_t format, uint32_t timeInterval, bool isMMAP)165 uint32_t CalculateFrameSize(uint32_t sampleRate, uint32_t channelCount,
166     int32_t format, uint32_t timeInterval, bool isMMAP)
167 {
168     return isMMAP ? (sampleRate * channelCount * static_cast<uint32_t>(format) * timeInterval) /
169                      AUDIO_MS_PER_SECOND : DEFAULT_AUDIO_DATA_SIZE;
170 }
171 
CalculateSampleNum(uint32_t sampleRate, uint32_t timems)172 int32_t CalculateSampleNum(uint32_t sampleRate, uint32_t timems)
173 {
174     return (sampleRate * timems) / AUDIO_MS_PER_SECOND;
175 }
176 
GetCurNano()177 int64_t GetCurNano()
178 {
179     int64_t result = -1;
180     struct timespec time;
181     clockid_t clockId = CLOCK_MONOTONIC;
182     int ret = clock_gettime(clockId, &time);
183     if (ret < 0) {
184         return result;
185     }
186     result = (time.tv_sec * AUDIO_NS_PER_SECOND) + time.tv_nsec;
187     return result;
188 }
189 
AbsoluteSleep(int64_t nanoTime)190 int32_t AbsoluteSleep(int64_t nanoTime)
191 {
192     int32_t ret = -1;
193     if (nanoTime <= 0) {
194         return ret;
195     }
196     struct timespec time;
197     time.tv_sec = nanoTime / AUDIO_NS_PER_SECOND;
198     time.tv_nsec = nanoTime - (time.tv_sec * AUDIO_NS_PER_SECOND);
199 
200     clockid_t clockId = CLOCK_MONOTONIC;
201     ret = clock_nanosleep(clockId, TIMER_ABSTIME, &time, nullptr);
202     return ret;
203 }
204 
CalculateOffset(const int64_t frameIndex, const int64_t framePeriodNs, const int64_t startTime)205 int64_t CalculateOffset(const int64_t frameIndex, const int64_t framePeriodNs, const int64_t startTime)
206 {
207     int64_t totalOffset = GetCurNano() - startTime;
208     return totalOffset - frameIndex * framePeriodNs;
209 }
210 
UpdateTimeOffset(const int64_t frameIndex, const int64_t framePeriodNs, int64_t &startTime)211 int64_t UpdateTimeOffset(const int64_t frameIndex, const int64_t framePeriodNs, int64_t &startTime)
212 {
213     int64_t timeOffset = 0;
214     if (frameIndex == 0) {
215         startTime = GetCurNano();
216     } else if (frameIndex % AUDIO_OFFSET_FRAME_NUM == 0) {
217         timeOffset = CalculateOffset(frameIndex, framePeriodNs, startTime);
218     }
219     return timeOffset;
220 }
221 
IsOutDurationRange(int64_t startTime, int64_t endTime, int64_t lastStartTime)222 bool IsOutDurationRange(int64_t startTime, int64_t endTime, int64_t lastStartTime)
223 {
224     int64_t currentInterval = endTime - startTime;
225     int64_t twiceInterval = startTime - lastStartTime;
226     return (currentInterval > MAX_TIME_INTERVAL_US || twiceInterval > MAX_TIME_INTERVAL_US) ? true : false;
227 }
228 
SaveFile(const std::string fileName, uint8_t *audioData, int32_t size)229 void SaveFile(const std::string fileName, uint8_t *audioData, int32_t size)
230 {
231     char path[PATH_MAX + 1] = {0x00};
232     if (fileName.length() > PATH_MAX || realpath(fileName.c_str(), path) == nullptr) {
233         DHLOGE("The file path is invalid.");
234         return;
235     }
236     std::ofstream ofs(path, std::ios::binary | std::ios::out | std::ios::app);
237     if (!ofs.is_open()) {
238         return;
239     }
240     ofs.write(reinterpret_cast<char *>(audioData), size);
241     ofs.close();
242 }
243 
WrapCJsonItem(const std::initializer_list<std::pair<std::string, std::string>> &keys, std::string &content)244 int32_t WrapCJsonItem(const std::initializer_list<std::pair<std::string, std::string>> &keys, std::string &content)
245 {
246     cJSON *jParam = cJSON_CreateObject();
247     if (jParam == nullptr) {
248         return ERR_DH_AUDIO_HDF_FAIL;
249     }
250     for (auto item : keys) {
251         cJSON_AddStringToObject(jParam, item.first.c_str(), item.second.c_str());
252     }
253     char *jsonData = cJSON_PrintUnformatted(jParam);
254     if (jsonData == nullptr) {
255         cJSON_Delete(jParam);
256         return ERR_DH_AUDIO_HDF_FAIL;
257     }
258     content = std::string(jsonData);
259     cJSON_Delete(jParam);
260     cJSON_free(jsonData);
261     return DH_SUCCESS;
262 }
263 
CJsonParamCheck(const cJSON *jsonObj, const std::initializer_list<std::string> &keys)264 bool CJsonParamCheck(const cJSON *jsonObj, const std::initializer_list<std::string> &keys)
265 {
266     if (jsonObj == nullptr || !cJSON_IsObject(jsonObj)) {
267         DHLOGE("JSON parameter is invalid.");
268         return false;
269     }
270 
271     for (auto it = keys.begin(); it != keys.end(); it++) {
272         cJSON *paramValue = cJSON_GetObjectItemCaseSensitive(jsonObj, (*it).c_str());
273         if (paramValue == nullptr) {
274             DHLOGE("JSON parameter does not contain key: %{public}s", (*it).c_str());
275             return false;
276         }
277     }
278     return true;
279 }
280 
ParseStringFromArgs(const std::string &args, const char *key)281 std::string ParseStringFromArgs(const std::string &args, const char *key)
282 {
283     DHLOGD("ParseStringFrom Args : %{public}s", args.c_str());
284     cJSON *jParam = cJSON_Parse(args.c_str());
285     if (jParam == nullptr) {
286         DHLOGE("Failed to parse JSON: %{public}s", cJSON_GetErrorPtr());
287         cJSON_Delete(jParam);
288         return "Failed to parse JSON";
289     }
290     if (!CJsonParamCheck(jParam, { key })) {
291         DHLOGE("Not found the key : %{public}s.", key);
292         cJSON_Delete(jParam);
293         return "Not found the key.";
294     }
295     cJSON *dhIdItem = cJSON_GetObjectItem(jParam, key);
296     if (dhIdItem == NULL || !cJSON_IsString(dhIdItem)) {
297         DHLOGE("Not found the value of the key : %{public}s.", key);
298         cJSON_Delete(jParam);
299         return "Not found the value.";
300     }
301     std::string content(dhIdItem->valuestring);
302     cJSON_Delete(jParam);
303     DHLOGD("Parsed string is: %{public}s.", content.c_str());
304     return content;
305 }
306 
307 template <typename T>
GetSysPara(const char *key, T &value)308 bool GetSysPara(const char *key, T &value)
309 {
310     CHECK_AND_RETURN_RET_LOG(key == nullptr, false, "key is nullptr");
311     char paraValue[30] = {0}; // 30 for system parameter
312     auto res = GetParameter(key, "-1", paraValue, sizeof(paraValue));
313 
314     CHECK_AND_RETURN_RET_LOG(res <= 0, false, "GetParameter fail, key:%{public}s res:%{public}d", key, res);
315     DHLOGI("GetSysPara key:%{public}s value:%{public}s", key, paraValue);
316     std::stringstream valueStr;
317     valueStr << paraValue;
318     valueStr >> value;
319     return true;
320 }
321 
322 template bool GetSysPara(const char *key, int32_t &value);
323 template bool GetSysPara(const char *key, uint32_t &value);
324 template bool GetSysPara(const char *key, int64_t &value);
325 template bool GetSysPara(const char *key, std::string &value);
326 
IsParamEnabled(const std::string &key, bool &isEnabled)327 bool IsParamEnabled(const std::string &key, bool &isEnabled)
328 {
329     // by default: old trans
330     int32_t policyFlag = 0;
331     if (GetSysPara(key.c_str(), policyFlag) && policyFlag == 1) {
332         isEnabled = true;
333         return true;
334     }
335     isEnabled = false;
336     return false;
337 }
338 
339 std::map<std::string, std::string> DumpFileUtil::g_lastPara = {};
340 
OpenDumpFileInner(const std::string &para, const std::string &fileName)341 FILE *DumpFileUtil::OpenDumpFileInner(const std::string &para, const std::string &fileName)
342 {
343     std::string filePath = DUMP_SERVICE_DIR + fileName;
344     std::string dumpPara;
345     FILE *dumpFile = nullptr;
346     bool res = GetSysPara(para.c_str(), dumpPara);
347     if (!res || dumpPara.empty()) {
348         DHLOGI("%{public}s is not set, dump dcamera is not required", para.c_str());
349         g_lastPara[para] = dumpPara;
350         return dumpFile;
351     }
352     DHLOGI("%{public}s = %{public}s, filePath: %{public}s", para.c_str(), dumpPara.c_str(), filePath.c_str());
353     if (dumpPara == "w") {
354         dumpFile = fopen(filePath.c_str(), "wb+");
355         CHECK_AND_RETURN_RET_LOG(dumpFile == nullptr, dumpFile, "Error opening dump file!");
356     } else if (dumpPara == "a") {
357         dumpFile = fopen(filePath.c_str(), "ab+");
358         CHECK_AND_RETURN_RET_LOG(dumpFile == nullptr, dumpFile, "Error opening dump file!");
359     }
360     g_lastPara[para] = dumpPara;
361     return dumpFile;
362 }
363 
WriteDumpFile(FILE *dumpFile, void *buffer, size_t bufferSize)364 void DumpFileUtil::WriteDumpFile(FILE *dumpFile, void *buffer, size_t bufferSize)
365 {
366     if (dumpFile == nullptr) {
367         return;
368     }
369     CHECK_AND_RETURN_LOG(buffer == nullptr, "Invalid write param");
370     size_t writeResult = fwrite(buffer, 1, bufferSize, dumpFile);
371     CHECK_AND_RETURN_LOG(writeResult != bufferSize, "Failed to write the file.");
372 }
373 
CloseDumpFile(FILE **dumpFile)374 void DumpFileUtil::CloseDumpFile(FILE **dumpFile)
375 {
376     CHECK_AND_RETURN_LOG(dumpFile == nullptr, "Invalid file para");
377     if (*dumpFile) {
378         fclose(*dumpFile);
379         *dumpFile = nullptr;
380     }
381 }
382 
ChangeDumpFileState(const std::string &para, FILE **dumpFile, const std::string &filePath)383 void DumpFileUtil::ChangeDumpFileState(const std::string &para, FILE **dumpFile, const std::string &filePath)
384 {
385     CHECK_AND_RETURN_LOG(dumpFile == nullptr || *dumpFile == nullptr, "Invalid file para");
386     CHECK_AND_RETURN_LOG(g_lastPara[para] != "w" || g_lastPara[para] != "a", "Invalid input para");
387     std::string dumpPara;
388     bool res = GetSysPara(para.c_str(), dumpPara);
389     if (!res || dumpPara.empty()) {
390         DHLOGE("get %{public}s fail", para.c_str());
391     }
392     if (g_lastPara[para] == "w" && dumpPara == "w") {
393         return;
394     }
395     CloseDumpFile(dumpFile);
396     OpenDumpFile(para, filePath, dumpFile);
397 }
398 
OpenDumpFile(const std::string &para, const std::string &fileName, FILE **file)399 void DumpFileUtil::OpenDumpFile(const std::string &para, const std::string &fileName, FILE **file)
400 {
401     CHECK_AND_RETURN_LOG(file == nullptr, "Invalid file para");
402     if (*file != nullptr) {
403         DumpFileUtil::ChangeDumpFileState(para, file, fileName);
404         return;
405     }
406 
407     if (para == DUMP_SERVER_PARA) {
408         *file = DumpFileUtil::OpenDumpFileInner(para, fileName);
409     }
410 }
411 } // namespace DistributedHardware
412 } // namespace OHOS