1 /*
2 * Copyright (c) 2022 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 <cinttypes>
17 #include <ctime>
18 #include <sstream>
19 #include <ostream>
20 #include "audio_utils.h"
21 #include "audio_utils_c.h"
22 #include "audio_errors.h"
23 #include "audio_log.h"
24 #ifdef FEATURE_HITRACE_METER
25 #include "hitrace_meter.h"
26 #endif
27 #include "parameter.h"
28 #include "tokenid_kit.h"
29 #include "ipc_skeleton.h"
30 #include "access_token.h"
31 #include "accesstoken_kit.h"
32 #include "xcollie/xcollie.h"
33 #include "xcollie/xcollie_define.h"
34
35 using OHOS::Security::AccessToken::AccessTokenKit;
36
37 namespace OHOS {
38 namespace AudioStandard {
GetCurNano()39 int64_t ClockTime::GetCurNano()
40 {
41 int64_t result = -1; // -1 for bad result.
42 struct timespec time;
43 clockid_t clockId = CLOCK_MONOTONIC;
44 int ret = clock_gettime(clockId, &time);
45 CHECK_AND_RETURN_RET_LOG(ret >= 0, result,
46 "GetCurNanoTime fail, result:%{public}d", ret);
47 result = (time.tv_sec * AUDIO_NS_PER_SECOND) + time.tv_nsec;
48 return result;
49 }
50
AbsoluteSleep(int64_t nanoTime)51 int32_t ClockTime::AbsoluteSleep(int64_t nanoTime)
52 {
53 int32_t ret = -1; // -1 for bad result.
54 CHECK_AND_RETURN_RET_LOG(nanoTime > 0, ret,
55 "AbsoluteSleep invalid sleep time :%{public}" PRId64 " ns", nanoTime);
56 struct timespec time;
57 time.tv_sec = nanoTime / AUDIO_NS_PER_SECOND;
58 time.tv_nsec = nanoTime - (time.tv_sec * AUDIO_NS_PER_SECOND); // Avoids % operation.
59
60 clockid_t clockId = CLOCK_MONOTONIC;
61 ret = clock_nanosleep(clockId, TIMER_ABSTIME, &time, nullptr);
62 if (ret != 0) {
63 AUDIO_WARNING_LOG("AbsoluteSleep may failed, ret is :%{public}d", ret);
64 }
65
66 return ret;
67 }
68
RelativeSleep(int64_t nanoTime)69 int32_t ClockTime::RelativeSleep(int64_t nanoTime)
70 {
71 int32_t ret = -1; // -1 for bad result.
72 CHECK_AND_RETURN_RET_LOG(nanoTime > 0, ret,
73 "AbsoluteSleep invalid sleep time :%{public}" PRId64 " ns", nanoTime);
74 struct timespec time;
75 time.tv_sec = nanoTime / AUDIO_NS_PER_SECOND;
76 time.tv_nsec = nanoTime - (time.tv_sec * AUDIO_NS_PER_SECOND); // Avoids % operation.
77
78 clockid_t clockId = CLOCK_MONOTONIC;
79 const int relativeFlag = 0; // flag of relative sleep.
80 ret = clock_nanosleep(clockId, relativeFlag, &time, nullptr);
81 if (ret != 0) {
82 AUDIO_WARNING_LOG("RelativeSleep may failed, ret is :%{public}d", ret);
83 }
84
85 return ret;
86 }
87
Count(const std::string & value,int64_t count,bool isEnable)88 void Trace::Count(const std::string &value, int64_t count, bool isEnable)
89 {
90 #ifdef FEATURE_HITRACE_METER
91 CountTraceDebug(isEnable, HITRACE_TAG_ZAUDIO, value, count);
92 #endif
93 }
94
Trace(const std::string & value,bool isShowLog,bool isEnable)95 Trace::Trace(const std::string &value, bool isShowLog, bool isEnable)
96 {
97 value_ = value;
98 isShowLog_ = isShowLog;
99 isEnable_ = isEnable;
100 isFinished_ = false;
101 #ifdef FEATURE_HITRACE_METER
102 if (isShowLog) {
103 isShowLog_ = true;
104 AUDIO_INFO_LOG("%{public}s start.", value_.c_str());
105 }
106 StartTraceDebug(isEnable_, HITRACE_TAG_ZAUDIO, value);
107 #endif
108 }
109
End()110 void Trace::End()
111 {
112 #ifdef FEATURE_HITRACE_METER
113 if (!isFinished_) {
114 FinishTraceDebug(isEnable_, HITRACE_TAG_ZAUDIO);
115 isFinished_ = true;
116 if (isShowLog_) {
117 AUDIO_INFO_LOG("%{public}s end.", value_.c_str());
118 }
119 }
120 #endif
121 }
122
~Trace()123 Trace::~Trace()
124 {
125 End();
126 }
127
AudioXCollie(const std::string & tag,uint32_t timeoutSeconds,std::function<void (void *)> func,void * arg,uint32_t flag)128 AudioXCollie::AudioXCollie(const std::string &tag, uint32_t timeoutSeconds,
129 std::function<void(void *)> func, void *arg, uint32_t flag)
130 {
131 AUDIO_DEBUG_LOG("Start AudioXCollie, tag: %{public}s, timeoutSeconds: %{public}u, flag: %{public}u",
132 tag.c_str(), timeoutSeconds, flag);
133 id_ = HiviewDFX::XCollie::GetInstance().SetTimer(tag, timeoutSeconds, func, arg, flag);
134 tag_ = tag;
135 isCanceled_ = false;
136 }
137
~AudioXCollie()138 AudioXCollie::~AudioXCollie()
139 {
140 CancelXCollieTimer();
141 }
142
CancelXCollieTimer()143 void AudioXCollie::CancelXCollieTimer()
144 {
145 if (!isCanceled_) {
146 HiviewDFX::XCollie::GetInstance().CancelTimer(id_);
147 isCanceled_ = true;
148 AUDIO_DEBUG_LOG("CancelXCollieTimer: cancel timer %{public}s", tag_.c_str());
149 }
150 }
151
VerifyIsSystemApp()152 bool PermissionUtil::VerifyIsSystemApp()
153 {
154 uint64_t fullTokenId = IPCSkeleton::GetCallingFullTokenID();
155 bool tmp = Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullTokenId);
156 CHECK_AND_RETURN_RET(!tmp, true);
157
158 AUDIO_ERR_LOG("Check system app permission reject");
159 return false;
160 }
161
VerifySelfPermission()162 bool PermissionUtil::VerifySelfPermission()
163 {
164 Security::AccessToken::FullTokenID selfToken = IPCSkeleton::GetSelfTokenID();
165
166 auto tokenTypeFlag = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(static_cast<uint32_t>(selfToken));
167
168 CHECK_AND_RETURN_RET(tokenTypeFlag != Security::AccessToken::TOKEN_NATIVE, true);
169
170 CHECK_AND_RETURN_RET(tokenTypeFlag != Security::AccessToken::TOKEN_SHELL, true);
171
172 bool tmp = Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken);
173 CHECK_AND_RETURN_RET(!tmp, true);
174
175 AUDIO_ERR_LOG("Check self app permission reject");
176 return false;
177 }
178
VerifySystemPermission()179 bool PermissionUtil::VerifySystemPermission()
180 {
181 auto tokenId = IPCSkeleton::GetCallingTokenID();
182 auto tokenTypeFlag = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
183
184 CHECK_AND_RETURN_RET(tokenTypeFlag != Security::AccessToken::TOKEN_NATIVE, true);
185
186 CHECK_AND_RETURN_RET(tokenTypeFlag != Security::AccessToken::TOKEN_SHELL, true);
187
188 bool tmp = VerifyIsSystemApp();
189 CHECK_AND_RETURN_RET(!tmp, true);
190
191 AUDIO_ERR_LOG("Check system permission reject");
192 return false;
193 }
194
AdjustStereoToMonoForPCM8Bit(int8_t * data,uint64_t len)195 void AdjustStereoToMonoForPCM8Bit(int8_t *data, uint64_t len)
196 {
197 // the number 2: stereo audio has 2 channels
198 uint64_t count = len / 2;
199
200 while (count > 0) {
201 // the number 2 is the count of stereo audio channels
202 data[0] = data[0] / 2 + data[1] / 2;
203 data[1] = data[0];
204 data += 2;
205 count--;
206 }
207 }
208
AdjustStereoToMonoForPCM16Bit(int16_t * data,uint64_t len)209 void AdjustStereoToMonoForPCM16Bit(int16_t *data, uint64_t len)
210 {
211 uint64_t count = len / 2 / 2;
212 // first number 2: stereo audio has 2 channels
213 // second number 2: the bit depth of PCM16Bit is 16 bits (2 bytes)
214
215 while (count > 0) {
216 // the number 2 is the count of stereo audio channels
217 data[0] = data[0] / 2 + data[1] / 2;
218 data[1] = data[0];
219 data += 2;
220 count--;
221 }
222 }
223
AdjustStereoToMonoForPCM24Bit(int8_t * data,uint64_t len)224 void AdjustStereoToMonoForPCM24Bit(int8_t *data, uint64_t len)
225 {
226 uint64_t count = len / 2 / 3;
227 // first number 2: stereo audio has 2 channels
228 // second number 3: the bit depth of PCM24Bit is 24 bits (3 bytes)
229
230 // int8_t is used for reading data of PCM24BIT here
231 // 24 / 8 = 3, so we need repeat the calculation three times in each loop
232 while (count > 0) {
233 // the number 2 is the count of stereo audio channels, 2 * 3 = 6
234 data[0] = data[0] / 2 + data[3] / 2;
235 data[3] = data[0];
236 data[1] = data[1] / 2 + data[4] / 2;
237 data[4] = data[1];
238 data[2] = data[2] / 2 + data[5] / 2;
239 data[5] = data[2];
240 data += 6;
241 count--;
242 }
243 }
244
AdjustStereoToMonoForPCM32Bit(int32_t * data,uint64_t len)245 void AdjustStereoToMonoForPCM32Bit(int32_t *data, uint64_t len)
246 {
247 uint64_t count = len / 2 / 4;
248 // first number 2: stereo audio has 2 channels
249 // second number 4: the bit depth of PCM32Bit is 32 bits (4 bytes)
250
251 while (count > 0) {
252 // the number 2 is the count of stereo audio channels
253 data[0] = data[0] / 2 + data[1] / 2;
254 data[1] = data[0];
255 data += 2;
256 count--;
257 }
258 }
259
AdjustAudioBalanceForPCM8Bit(int8_t * data,uint64_t len,float left,float right)260 void AdjustAudioBalanceForPCM8Bit(int8_t *data, uint64_t len, float left, float right)
261 {
262 uint64_t count = len / 2;
263 // the number 2: stereo audio has 2 channels
264
265 while (count > 0) {
266 // the number 2 is the count of stereo audio channels
267 data[0] *= left;
268 data[1] *= right;
269 data += 2;
270 count--;
271 }
272 }
273
AdjustAudioBalanceForPCM16Bit(int16_t * data,uint64_t len,float left,float right)274 void AdjustAudioBalanceForPCM16Bit(int16_t *data, uint64_t len, float left, float right)
275 {
276 uint64_t count = len / 2 / 2;
277 // first number 2: stereo audio has 2 channels
278 // second number 2: the bit depth of PCM16Bit is 16 bits (2 bytes)
279
280 while (count > 0) {
281 // the number 2 is the count of stereo audio channels
282 data[0] *= left;
283 data[1] *= right;
284 data += 2;
285 count--;
286 }
287 }
288
AdjustAudioBalanceForPCM24Bit(int8_t * data,uint64_t len,float left,float right)289 void AdjustAudioBalanceForPCM24Bit(int8_t *data, uint64_t len, float left, float right)
290 {
291 uint64_t count = len / 2 / 3;
292 // first number 2: stereo audio has 2 channels
293 // second number 3: the bit depth of PCM24Bit is 24 bits (3 bytes)
294
295 // int8_t is used for reading data of PCM24BIT here
296 // 24 / 8 = 3, so we need repeat the calculation three times in each loop
297 while (count > 0) {
298 // the number 2 is the count of stereo audio channels, 2 * 3 = 6
299 data[0] *= left;
300 data[1] *= left;
301 data[2] *= left;
302 data[3] *= right;
303 data[4] *= right;
304 data[5] *= right;
305 data += 6;
306 count--;
307 }
308 }
309
AdjustAudioBalanceForPCM32Bit(int32_t * data,uint64_t len,float left,float right)310 void AdjustAudioBalanceForPCM32Bit(int32_t *data, uint64_t len, float left, float right)
311 {
312 uint64_t count = len / 2 / 4;
313 // first number 2: stereo audio has 2 channels
314 // second number 4: the bit depth of PCM32Bit is 32 bits (4 bytes)
315
316 while (count > 0) {
317 // the number 2 is the count of stereo audio channels
318 data[0] *= left;
319 data[1] *= right;
320 data += 2;
321 count--;
322 }
323 }
324
Read24Bit(const uint8_t * p)325 uint32_t Read24Bit(const uint8_t *p)
326 {
327 return ((uint32_t) p[BIT_DEPTH_TWO] << BIT_16) | ((uint32_t) p[1] << BIT_8) | ((uint32_t) p[0]);
328 }
329
Write24Bit(uint8_t * p,uint32_t u)330 void Write24Bit(uint8_t *p, uint32_t u)
331 {
332 p[BIT_DEPTH_TWO] = (uint8_t) (u >> BIT_16);
333 p[1] = static_cast<uint8_t>(u >> BIT_8);
334 p[0] = static_cast<uint8_t>(u);
335 }
336
ConvertFrom24BitToFloat(unsigned n,const uint8_t * a,float * b)337 void ConvertFrom24BitToFloat(unsigned n, const uint8_t *a, float *b)
338 {
339 for (; n > 0; n--) {
340 int32_t s = Read24Bit(a) << BIT_8;
341 *b = s * (1.0f / (1U << (BIT_32 - 1)));
342 a += OFFSET_BIT_24;
343 b++;
344 }
345 }
346
ConvertFrom32BitToFloat(unsigned n,const int32_t * a,float * b)347 void ConvertFrom32BitToFloat(unsigned n, const int32_t *a, float *b)
348 {
349 for (; n > 0; n--) {
350 *(b++) = *(a++) * (1.0f / (1U << (BIT_32 - 1)));
351 }
352 }
353
CapMax(float v)354 float CapMax(float v)
355 {
356 float value = v;
357 if (v > 1.0f) {
358 value = 1.0f - FLOAT_EPS;
359 } else if (v < -1.0f) {
360 value = -1.0f + FLOAT_EPS;
361 }
362 return value;
363 }
364
ConvertFromFloatTo24Bit(unsigned n,const float * a,uint8_t * b)365 void ConvertFromFloatTo24Bit(unsigned n, const float *a, uint8_t *b)
366 {
367 for (; n > 0; n--) {
368 float tmp = *a++;
369 float v = CapMax(tmp) * (1U << (BIT_32 - 1));
370 Write24Bit(b, (static_cast<int32_t>(v)) >> BIT_8);
371 b += OFFSET_BIT_24;
372 }
373 }
374
ConvertFromFloatTo32Bit(unsigned n,const float * a,int32_t * b)375 void ConvertFromFloatTo32Bit(unsigned n, const float *a, int32_t *b)
376 {
377 for (; n > 0; n--) {
378 float tmp = *a++;
379 float v = CapMax(tmp) * (1U << (BIT_32 - 1));
380 *(b++) = static_cast<int32_t>(v);
381 }
382 }
383
384 template <typename T>
GetSysPara(const char * key,T & value)385 bool GetSysPara(const char *key, T &value)
386 {
387 CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr");
388 char paraValue[20] = {0}; // 20 for system parameter
389 auto res = GetParameter(key, "-1", paraValue, sizeof(paraValue));
390
391 CHECK_AND_RETURN_RET_LOG(res > 0, false, "GetSysPara fail, key:%{public}s res:%{public}d", key, res);
392 AUDIO_DEBUG_LOG("key:%{public}s value:%{public}s", key, paraValue);
393 std::stringstream valueStr;
394 valueStr << paraValue;
395 valueStr >> value;
396 return true;
397 }
398
399 template bool GetSysPara(const char *key, int32_t &value);
400 template bool GetSysPara(const char *key, uint32_t &value);
401 template bool GetSysPara(const char *key, int64_t &value);
402 template bool GetSysPara(const char *key, std::string &value);
403
404 std::map<std::string, std::string> DumpFileUtil::g_lastPara = {};
405
OpenDumpFileInner(std::string para,std::string fileName,AudioDumpFileType fileType)406 FILE *DumpFileUtil::OpenDumpFileInner(std::string para, std::string fileName, AudioDumpFileType fileType)
407 {
408 std::string filePath;
409 switch (fileType) {
410 case AUDIO_APP:
411 filePath = DUMP_APP_DIR + fileName;
412 break;
413 case AUDIO_SERVICE:
414 filePath = DUMP_SERVICE_DIR + fileName;
415 break;
416 case AUDIO_PULSE:
417 filePath = DUMP_PULSE_DIR + fileName;
418 break;
419 default:
420 AUDIO_ERR_LOG("Invalid AudioDumpFileType");
421 break;
422 }
423 std::string dumpPara;
424 FILE *dumpFile = nullptr;
425 bool res = GetSysPara(para.c_str(), dumpPara);
426 if (!res || dumpPara.empty()) {
427 AUDIO_INFO_LOG("%{public}s is not set, dump audio is not required", para.c_str());
428 g_lastPara[para] = dumpPara;
429 return dumpFile;
430 }
431 AUDIO_DEBUG_LOG("%{public}s = %{public}s", para.c_str(), dumpPara.c_str());
432 if (dumpPara == "w") {
433 dumpFile = fopen(filePath.c_str(), "wb+");
434 CHECK_AND_RETURN_RET_LOG(dumpFile != nullptr, dumpFile,
435 "Error opening pcm test file!");
436 } else if (dumpPara == "a") {
437 dumpFile = fopen(filePath.c_str(), "ab+");
438 CHECK_AND_RETURN_RET_LOG(dumpFile != nullptr, dumpFile,
439 "Error opening pcm test file!");
440 }
441 g_lastPara[para] = dumpPara;
442 return dumpFile;
443 }
444
WriteDumpFile(FILE * dumpFile,void * buffer,size_t bufferSize)445 void DumpFileUtil::WriteDumpFile(FILE *dumpFile, void *buffer, size_t bufferSize)
446 {
447 if (dumpFile == nullptr) {
448 return;
449 }
450 CHECK_AND_RETURN_LOG(buffer != nullptr, "Invalid write param");
451 size_t writeResult = fwrite(buffer, 1, bufferSize, dumpFile);
452 CHECK_AND_RETURN_LOG(writeResult == bufferSize, "Failed to write the file.");
453 }
454
CloseDumpFile(FILE ** dumpFile)455 void DumpFileUtil::CloseDumpFile(FILE **dumpFile)
456 {
457 if (*dumpFile) {
458 fclose(*dumpFile);
459 *dumpFile = nullptr;
460 }
461 }
462
ChangeDumpFileState(std::string para,FILE ** dumpFile,std::string filePath)463 void DumpFileUtil::ChangeDumpFileState(std::string para, FILE **dumpFile, std::string filePath)
464 {
465 CHECK_AND_RETURN_LOG(*dumpFile != nullptr, "Invalid file para");
466 CHECK_AND_RETURN_LOG(g_lastPara[para] == "w" || g_lastPara[para] == "a", "Invalid input para");
467 std::string dumpPara;
468 bool res = GetSysPara(para.c_str(), dumpPara);
469 if (!res || dumpPara.empty()) {
470 AUDIO_WARNING_LOG("get %{public}s fail", para.c_str());
471 }
472 if (g_lastPara[para] == "w" && dumpPara == "w") {
473 return;
474 }
475 CloseDumpFile(dumpFile);
476 OpenDumpFile(para, filePath, dumpFile);
477 }
478
OpenDumpFile(std::string para,std::string fileName,FILE ** file)479 void DumpFileUtil::OpenDumpFile(std::string para, std::string fileName, FILE **file)
480 {
481 if (*file != nullptr) {
482 DumpFileUtil::ChangeDumpFileState(para, file, fileName);
483 return;
484 }
485 if (para == DUMP_SERVER_PARA) {
486 if (fileName == DUMP_BLUETOOTH_RENDER_SINK_FILENAME || fileName == DUMP_RENDER_SINK_FILENAME ||
487 fileName == DUMP_CAPTURER_SOURCE_FILENAME || fileName == DUMP_OFFLOAD_RENDER_SINK_FILENAME) {
488 *file = DumpFileUtil::OpenDumpFileInner(para, fileName, AUDIO_PULSE);
489 return;
490 }
491 *file = DumpFileUtil::OpenDumpFileInner(para, fileName, AUDIO_SERVICE);
492 } else {
493 *file = DumpFileUtil::OpenDumpFileInner(para, fileName, AUDIO_APP);
494 if (*file == nullptr) {
495 *file = DumpFileUtil::OpenDumpFileInner(para, fileName, AUDIO_SERVICE);
496 }
497 }
498 }
499
500 } // namespace AudioStandard
501 } // namespace OHOS
502
503 #ifdef __cplusplus
504 extern "C" {
505 #endif
506
507 struct CTrace {
CTraceCTrace508 explicit CTrace(const char *traceName) : trace(OHOS::AudioStandard::Trace(traceName)) {};
509 OHOS::AudioStandard::Trace trace;
510 };
511
GetAndStart(const char * traceName)512 CTrace *GetAndStart(const char *traceName)
513 {
514 std::unique_ptr<CTrace> cTrace = std::make_unique<CTrace>(traceName);
515
516 return cTrace.release();
517 }
518
EndCTrace(CTrace * cTrace)519 void EndCTrace(CTrace *cTrace)
520 {
521 if (cTrace != nullptr) {
522 cTrace->trace.End();
523 }
524 }
525
CTraceCount(const char * traceName,int64_t count)526 void CTraceCount(const char *traceName, int64_t count)
527 {
528 OHOS::AudioStandard::Trace::Count(traceName, count);
529 }
530
CallEndAndClear(CTrace ** cTrace)531 void CallEndAndClear(CTrace **cTrace)
532 {
533 if (cTrace != nullptr && *cTrace != nullptr) {
534 EndCTrace(*cTrace);
535 delete *cTrace;
536 *cTrace = nullptr;
537 }
538 }
539
540 #ifdef __cplusplus
541 }
542 #endif
543