1 /*
2 * Copyright (c) 2025 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 #include <inttypes.h>
16 #include "audio_stream_checker.h"
17 #include "audio_renderer_log.h"
18 #include "audio_utils.h"
19 #include "audio_stream_monitor.h"
20 #include "volume_tools.h"
21
22 namespace OHOS {
23 namespace AudioStandard {
24 namespace {
25 const float TRANS_PERCENTAGE = 100.0;
26 const int32_t TRANS_INTEGER = 100;
27 const int32_t AUDIOSTREAM_LATENCY_MODE_NORMAL = 0;
28 const int64_t STREAM_CHECK_INTERVAL_TIME = 500000000; // 500ms
29 const int64_t DEFAULT_TIME = 0;
30 const int64_t NORMAL_FRAME_PER_TIME = 20000000; // 20ms
31 const int64_t FAST_FRAME_PER_TIME = 5000000; // 5ms
32 }
33
AudioStreamChecker(AudioProcessConfig cfg)34 AudioStreamChecker::AudioStreamChecker(AudioProcessConfig cfg) : streamConfig_(cfg)
35 {
36 monitorSwitch_ = true;
37 }
38
~AudioStreamChecker()39 AudioStreamChecker::~AudioStreamChecker()
40 {
41 AUDIO_INFO_LOG("~AudioStreamChecker(), sessionId = %{public}u, uid = %{public}d",
42 streamConfig_.originalSessionId, streamConfig_.appInfo.appUid);
43 monitorSwitch_ = false;
44 isKeepCheck_.store(false);
45 }
46
InitChecker(DataTransferMonitorParam para,const int32_t pid,const int32_t callbackId)47 void AudioStreamChecker::InitChecker(DataTransferMonitorParam para, const int32_t pid, const int32_t callbackId)
48 {
49 std::lock_guard<std::recursive_mutex> lock(checkLock_);
50 for (auto item : checkParaVector_) {
51 if (item.callbackId == callbackId && item.pid == pid) {
52 AUDIO_INFO_LOG("No need init check, callbackid = %{public}d, pid = %{public}d", callbackId, pid);
53 return;
54 }
55 }
56 CheckerParam checkPara;
57 checkPara.pid = pid;
58 checkPara.callbackId = callbackId;
59 checkPara.para = para;
60 checkPara.hasInitCheck = true;
61 checkPara.isMonitorMuteFrame = IsMonitorMuteFrame(checkPara);
62 checkPara.isMonitorNoDataFrame = IsMonitorNoDataFrame(checkPara);
63 checkPara.lastUpdateTime = ClockTime::GetCurNano();
64 checkParaVector_.push_back(checkPara);
65 if (isNeedCreateThread_.load()) {
66 isKeepCheck_.store(true);
67 std::weak_ptr<AudioStreamChecker> self = shared_from_this();
68 checkThread_ = std::thread([self] {
69 if (auto thisPtr = self.lock()) {
70 thisPtr->CheckStreamThread();
71 }
72 });
73 pthread_setname_np(checkThread_.native_handle(), "OS_CheckStreamLoop");
74 checkThread_.detach();
75 isNeedCreateThread_.store(false);
76 AUDIO_INFO_LOG("Start check thread success");
77 }
78 AUDIO_INFO_LOG("Init checker end, pid = %{public}d, callbackId = %{public}d, uid = %{public}d",
79 pid, callbackId, para.clientUID);
80 }
81
DeleteCheckerPara(const int32_t pid,const int32_t callbackId)82 void AudioStreamChecker::DeleteCheckerPara(const int32_t pid, const int32_t callbackId)
83 {
84 std::lock_guard<std::recursive_mutex> lock(checkLock_);
85 for (auto iter = checkParaVector_.begin(); iter != checkParaVector_.end();) {
86 if (iter->pid == pid && iter->callbackId == callbackId) {
87 iter = checkParaVector_.erase(iter);
88 AUDIO_INFO_LOG("Delete check para success, pid = %{public}d, callbackId = %{public}d,",
89 pid, callbackId);
90 } else {
91 iter++;
92 }
93 }
94 if (checkParaVector_.size() == 0) {
95 isNeedCreateThread_.store(true);
96 isKeepCheck_.store(false);
97 AUDIO_INFO_LOG("Stream has no callback, stop check thread");
98 }
99 AUDIO_INFO_LOG("Delete check para end, pid = %{public}d, callbackId = %{public}d", pid, callbackId);
100 }
101
CalculateFrameAfterStandby(CheckerParam & para,int64_t & abnormalFrameNum)102 void AudioStreamChecker::CalculateFrameAfterStandby(CheckerParam ¶, int64_t &abnormalFrameNum)
103 {
104 int64_t timePerFrame = (streamConfig_.rendererInfo.rendererFlags == AUDIOSTREAM_LATENCY_MODE_NORMAL) ?
105 NORMAL_FRAME_PER_TIME : FAST_FRAME_PER_TIME;
106 AUDIO_DEBUG_LOG("Frame per time = %{public}" PRId64"", timePerFrame);
107 AUDIO_DEBUG_LOG("StandbyStartTime = %{public}" PRId64", StandbyStopTime = %{public}" PRId64"",
108 para.standbyStartTime, para.standbyStopTime);
109 AUDIO_DEBUG_LOG("IsInStandby = %{public}d", para.isInStandby);
110 int64_t calculateFrameNum = 0;
111 if (para.standbyStartTime != DEFAULT_TIME && para.standbyStopTime != DEFAULT_TIME) {
112 calculateFrameNum = ((para.standbyStopTime - para.standbyStartTime) / timePerFrame);
113 } else if (para.standbyStartTime != DEFAULT_TIME && para.standbyStopTime == DEFAULT_TIME) {
114 calculateFrameNum = ((ClockTime::GetCurNano() - para.standbyStartTime) / timePerFrame);
115 AUDIO_DEBUG_LOG("Current time = %{public}" PRId64"", ClockTime::GetCurNano());
116 } else if (para.standbyStartTime == DEFAULT_TIME && para.standbyStopTime != DEFAULT_TIME) {
117 calculateFrameNum = ((para.standbyStopTime - para.lastUpdateTime) / timePerFrame);
118 AUDIO_DEBUG_LOG("Last update time = %{public}" PRId64"", para.lastUpdateTime);
119 } else {
120 calculateFrameNum = (para.isInStandby ? (para.para.timeInterval / timePerFrame) : 0);
121 }
122 AUDIO_DEBUG_LOG("Calculate no data frame num = %{public}" PRId64"", calculateFrameNum);
123 if (para.isMonitorNoDataFrame) {
124 abnormalFrameNum += calculateFrameNum;
125 }
126 para.noDataFrameNum += calculateFrameNum;
127 AUDIO_DEBUG_LOG("AbnormalFrameNum = %{public}" PRId64", NoDataFrameNum = %{public}" PRId64"",
128 abnormalFrameNum, para.noDataFrameNum);
129 }
130
OnRemoteAppDied(const int32_t pid)131 void AudioStreamChecker::OnRemoteAppDied(const int32_t pid)
132 {
133 std::lock_guard<std::recursive_mutex> lock(checkLock_);
134 for (auto iter = checkParaVector_.begin(); iter != checkParaVector_.end();) {
135 if (iter->pid == pid) {
136 iter = checkParaVector_.erase(iter);
137 AUDIO_INFO_LOG("Delete check para success when remote app died, pid = %{public}d", pid);
138 } else {
139 iter++;
140 }
141 }
142 if (checkParaVector_.size() == 0) {
143 isNeedCreateThread_.store(true);
144 isKeepCheck_.store(false);
145 AUDIO_INFO_LOG("Stream has no callback when remote app died, stop check thread");
146 }
147 AUDIO_INFO_LOG("Delete check para end when remote app died, pid = %{public}d", pid);
148 }
149
StopCheckStreamThread()150 void AudioStreamChecker::StopCheckStreamThread()
151 {
152 AUDIO_INFO_LOG("In");
153 isKeepCheck_.store(false);
154 }
155
CheckStreamThread()156 void AudioStreamChecker::CheckStreamThread()
157 {
158 AUDIO_INFO_LOG("In");
159 while (isKeepCheck_.load()) {
160 MonitorCheckFrame();
161 CheckVolume();
162 ClockTime::RelativeSleep(STREAM_CHECK_INTERVAL_TIME);
163 }
164 AUDIO_INFO_LOG("Out");
165 }
166
CheckVolume()167 void AudioStreamChecker::CheckVolume()
168 {
169 std::lock_guard<std::mutex> lock(volumeLock_);
170 if (VolumeTools::IsZeroVolume(curVolume_) && !VolumeTools::IsZeroVolume(preVolume_)) {
171 AUDIO_INFO_LOG("sessionId %{public}u change to mute", streamConfig_.originalSessionId);
172 std::unique_lock<std::recursive_mutex> lock(checkLock_);
173 for (size_t index = 0; index < checkParaVector_.size(); index++) {
174 AudioStreamMonitor::GetInstance().OnMuteCallback(checkParaVector_[index].pid,
175 checkParaVector_[index].callbackId, streamConfig_.appInfo.appUid,
176 streamConfig_.originalSessionId, true);
177 }
178 lock.unlock();
179 }
180 if (!VolumeTools::IsZeroVolume(curVolume_) && VolumeTools::IsZeroVolume(preVolume_)) {
181 AUDIO_INFO_LOG("sessionId %{public}u change to unmute", streamConfig_.originalSessionId);
182 std::unique_lock<std::recursive_mutex> lock(checkLock_);
183 for (size_t index = 0; index < checkParaVector_.size(); index++) {
184 AudioStreamMonitor::GetInstance().OnMuteCallback(checkParaVector_[index].pid,
185 checkParaVector_[index].callbackId, streamConfig_.appInfo.appUid,
186 streamConfig_.originalSessionId, false);
187 }
188 lock.unlock();
189 }
190 preVolume_ = curVolume_;
191 }
192
MonitorCheckFrame()193 void AudioStreamChecker::MonitorCheckFrame()
194 {
195 if (!monitorSwitch_) {
196 AUDIO_INFO_LOG("Not register monitor callback");
197 return;
198 }
199 std::lock_guard<std::recursive_mutex> lock(checkLock_);
200 for (int32_t index = 0; index < checkParaVector_.size(); index++) {
201 MonitorCheckFrameSub(checkParaVector_[index]);
202 }
203 }
204
MonitorCheckFrameAction(CheckerParam & para,int64_t abnormalFrameNum,float badFrameRatio)205 void AudioStreamChecker::MonitorCheckFrameAction(CheckerParam ¶, int64_t abnormalFrameNum,
206 float badFrameRatio)
207 {
208 if (abnormalFrameNum >= static_cast<int64_t>(para.sumFrameCount * badFrameRatio)) {
209 if (para.lastStatus == DATA_TRANS_STOP) {
210 AUDIO_DEBUG_LOG("sessionId = %{public}u, status still in DATA_TRANS_STOP",
211 streamConfig_.originalSessionId);
212 MonitorOnCallback(DATA_TRANS_STOP, false, para);
213 } else if (para.lastStatus == AUDIO_STREAM_PAUSE) {
214 AUDIO_DEBUG_LOG("Last status is AUDIO_STREAM_PAUSE, no need callback");
215 CleanRecordData(para);
216 } else {
217 AUDIO_DEBUG_LOG("sessionId = %{public}u, status change in DATA_TRANS_STOP",
218 streamConfig_.originalSessionId);
219 MonitorOnCallback(DATA_TRANS_STOP, true, para);
220 }
221 } else {
222 if (para.lastStatus == DATA_TRANS_RESUME) {
223 AUDIO_DEBUG_LOG("sessionId = %{public}u, status still in DATA_TRANS_RESUME",
224 streamConfig_.originalSessionId);
225 MonitorOnCallback(DATA_TRANS_RESUME, false, para);
226 } else if (para.lastStatus == AUDIO_STREAM_START || para.lastStatus == AUDIO_STREAM_PAUSE) {
227 AUDIO_DEBUG_LOG("Last status is %{public}d, no need callback", para.lastStatus);
228 para.lastStatus = para.lastStatus == AUDIO_STREAM_START ? DATA_TRANS_RESUME : AUDIO_STREAM_PAUSE;
229 CleanRecordData(para);
230 } else {
231 AUDIO_DEBUG_LOG("sessionId = %{public}u, status change in DATA_TRANS_RESUME",
232 streamConfig_.originalSessionId);
233 MonitorOnCallback(DATA_TRANS_RESUME, true, para);
234 }
235 }
236 }
237
MonitorCheckFrameSub(CheckerParam & para)238 void AudioStreamChecker::MonitorCheckFrameSub(CheckerParam ¶)
239 {
240 if (!para.hasInitCheck) {
241 AUDIO_ERR_LOG("Check para not init, appuid = %{public}d", para.para.clientUID);
242 return;
243 }
244 int64_t timeCost = ClockTime::GetCurNano() - para.lastUpdateTime;
245 int64_t abnormalFrameNum = 0;
246 if (para.isMonitorMuteFrame) {
247 abnormalFrameNum += para.muteFrameNum;
248 AUDIO_DEBUG_LOG("Check mute frame size = %{public}" PRId64, para.muteFrameNum);
249 }
250 if (para.isMonitorNoDataFrame) {
251 abnormalFrameNum += para.noDataFrameNum;
252 AUDIO_DEBUG_LOG("Check no data frame size = %{public}" PRId64, para.noDataFrameNum);
253 }
254
255 if (timeCost < para.para.timeInterval) {
256 AUDIO_DEBUG_LOG("Check time is not enough");
257 return;
258 }
259 AUDIO_DEBUG_LOG("Before calculate abnormalFrameNum = %{public}" PRId64"", abnormalFrameNum);
260 CalculateFrameAfterStandby(para, abnormalFrameNum);
261 para.sumFrameCount = para.normalFrameCount + para.noDataFrameNum;
262 float badFrameRatio = para.para.badFramesRatio / TRANS_PERCENTAGE;
263 AUDIO_DEBUG_LOG("Check frame sum = %{public}" PRId64", abnormal = %{public}" PRId64", badRatio = %{public}f",
264 para.sumFrameCount, abnormalFrameNum, badFrameRatio);
265 AUDIO_DEBUG_LOG("Last check status = %{public}d", para.lastStatus);
266 MonitorCheckFrameAction(para, abnormalFrameNum, badFrameRatio);
267 }
268
CleanRecordData(CheckerParam & para)269 void AudioStreamChecker::CleanRecordData(CheckerParam ¶)
270 {
271 para.muteFrameNum = 0;
272 para.noDataFrameNum = 0;
273 para.normalFrameCount = 0;
274 para.sumFrameCount = 0;
275 para.standbyStartTime = 0;
276 para.standbyStopTime = 0;
277 para.lastUpdateTime = ClockTime::GetCurNano();
278 AUDIO_DEBUG_LOG("Clean check para end...");
279 }
280
MonitorOnAllCallback(DataTransferStateChangeType type,bool isStandby)281 void AudioStreamChecker::MonitorOnAllCallback(DataTransferStateChangeType type, bool isStandby)
282 {
283 std::lock_guard<std::recursive_mutex> lock(checkLock_);
284 if (!monitorSwitch_) {
285 AUDIO_ERR_LOG("Not register monitor callback");
286 return;
287 }
288 AudioRendererDataTransferStateChangeInfo callbackInfo;
289 InitCallbackInfo(type, callbackInfo);
290 for (size_t index = 0; index < checkParaVector_.size(); index++) {
291 if (isStandby && type == DATA_TRANS_RESUME && !checkParaVector_[index].isMonitorNoDataFrame) {
292 AUDIO_INFO_LOG("Start during standby and no monitor nodata frame, no need callback");
293 continue;
294 }
295 checkParaVector_[index].lastStatus = type;
296 AUDIO_INFO_LOG("type = %{public}d", type);
297 checkParaVector_[index].lastUpdateTime = ClockTime::GetCurNano();
298 CleanRecordData(checkParaVector_[index]);
299 AudioRendererDataTransferStateChangeInfo callbackInfo;
300 InitCallbackInfo(type, callbackInfo);
301 AudioStreamMonitor::GetInstance().OnCallback(checkParaVector_[index].pid,
302 checkParaVector_[index].callbackId, callbackInfo);
303 }
304 }
305
RecordStandbyTime(bool isStandbyStart)306 void AudioStreamChecker::RecordStandbyTime(bool isStandbyStart)
307 {
308 std::lock_guard<std::recursive_mutex> lock(checkLock_);
309 for (size_t index = 0; index < checkParaVector_.size(); index++) {
310 if (isStandbyStart) {
311 checkParaVector_[index].standbyStartTime = ClockTime::GetCurNano();
312 } else {
313 checkParaVector_[index].standbyStopTime = ClockTime::GetCurNano();
314 }
315 checkParaVector_[index].isInStandby = isStandbyStart;
316 }
317 }
318
InitCallbackInfo(DataTransferStateChangeType type,AudioRendererDataTransferStateChangeInfo & callbackInfo)319 void AudioStreamChecker::InitCallbackInfo(DataTransferStateChangeType type,
320 AudioRendererDataTransferStateChangeInfo &callbackInfo)
321 {
322 callbackInfo.stateChangeType = type;
323 callbackInfo.clientPid = streamConfig_.appInfo.appPid;
324 callbackInfo.clientUID = streamConfig_.appInfo.appUid;
325 callbackInfo.streamUsage = streamConfig_.rendererInfo.streamUsage;
326 callbackInfo.sessionId = streamConfig_.originalSessionId;
327 {
328 std::lock_guard<std::recursive_mutex> lock(backgroundStateLock_);
329 callbackInfo.isBackground = isBackground_;
330 }
331 }
332
MonitorOnCallback(DataTransferStateChangeType type,bool isNeedCallback,CheckerParam & para)333 void AudioStreamChecker::MonitorOnCallback(DataTransferStateChangeType type, bool isNeedCallback, CheckerParam ¶)
334 {
335 para.lastUpdateTime = ClockTime::GetCurNano();
336 if (!monitorSwitch_ || !para.hasInitCheck) {
337 return;
338 }
339 if (para.sumFrameCount == 0) {
340 AUDIO_DEBUG_LOG("Audio stream not start, callbackId = %{public}d", para.callbackId);
341 return;
342 }
343 para.lastStatus = type;
344 AudioRendererDataTransferStateChangeInfo callbackInfo;
345 InitCallbackInfo(type, callbackInfo);
346 callbackInfo.badDataRatio[NO_DATA_TRANS] = (para.noDataFrameNum * TRANS_INTEGER) / para.sumFrameCount;
347 callbackInfo.badDataRatio[SILENCE_DATA_TRANS] = (para.muteFrameNum * TRANS_INTEGER) / para.sumFrameCount;
348 AUDIO_DEBUG_LOG("NO_DATA_TRANS ration = %{public}d, SILENCE_DATA_TRANS ratio = %{public}d",
349 callbackInfo.badDataRatio[NO_DATA_TRANS], callbackInfo.badDataRatio[SILENCE_DATA_TRANS]);
350 if (isNeedCallback) {
351 AUDIO_DEBUG_LOG("Callback stream status, pid = %{public}d, callbackId = %{public}d",
352 para.pid, para.callbackId);
353 AudioStreamMonitor::GetInstance().OnCallback(para.pid, para.callbackId, callbackInfo);
354 }
355 CleanRecordData(para);
356 }
357
IsMonitorMuteFrame(const CheckerParam & para)358 bool AudioStreamChecker::IsMonitorMuteFrame(const CheckerParam ¶)
359 {
360 AUDIO_INFO_LOG("badDataTransferTypeBitMap = %{public}d", para.para.badDataTransferTypeBitMap);
361 if (para.hasInitCheck) {
362 return para.para.badDataTransferTypeBitMap & (1 << SILENCE_DATA_TRANS);
363 }
364 return false;
365 }
366
IsMonitorNoDataFrame(const CheckerParam & para)367 bool AudioStreamChecker::IsMonitorNoDataFrame(const CheckerParam ¶)
368 {
369 AUDIO_INFO_LOG("badDataTransferTypeBitMap = %{public}d", para.para.badDataTransferTypeBitMap);
370 if (para.hasInitCheck) {
371 return para.para.badDataTransferTypeBitMap & (1 << NO_DATA_TRANS);
372 }
373 return false;
374 }
375
GetAppUid()376 int32_t AudioStreamChecker::GetAppUid()
377 {
378 return streamConfig_.appInfo.appUid;
379 }
380
RecordMuteFrame()381 void AudioStreamChecker::RecordMuteFrame()
382 {
383 std::lock_guard<std::recursive_mutex> lock(checkLock_);
384 for (size_t index = 0; index < checkParaVector_.size(); index++) {
385 checkParaVector_[index].muteFrameNum++;
386 AUDIO_DEBUG_LOG("Mute frame num = %{public}" PRId64", callbackId = %{public}d",
387 checkParaVector_[index].muteFrameNum, checkParaVector_[index].callbackId);
388 }
389 }
390
RecordNodataFrame()391 void AudioStreamChecker::RecordNodataFrame()
392 {
393 std::lock_guard<std::recursive_mutex> lock(checkLock_);
394 for (size_t index = 0; index < checkParaVector_.size(); index++) {
395 checkParaVector_[index].noDataFrameNum++;
396 AUDIO_DEBUG_LOG("No data frame num = %{public}" PRId64", callbackId = %{public}d",
397 checkParaVector_[index].noDataFrameNum, checkParaVector_[index].callbackId);
398 }
399 }
400
RecordNormalFrame()401 void AudioStreamChecker::RecordNormalFrame()
402 {
403 std::lock_guard<std::recursive_mutex> lock(checkLock_);
404 for (size_t index = 0; index < checkParaVector_.size(); index++) {
405 checkParaVector_[index].normalFrameCount++;
406 AUDIO_DEBUG_LOG("Normal frame num = %{public}" PRId64", callbackId = %{public}d",
407 checkParaVector_[index].normalFrameCount, checkParaVector_[index].callbackId);
408 }
409 }
410
UpdateAppState(bool isBackground)411 void AudioStreamChecker::UpdateAppState(bool isBackground)
412 {
413 {
414 std::lock_guard<std::recursive_mutex> lock(backgroundStateLock_);
415 isBackground_ = isBackground;
416 }
417 }
418
SetVolume(float volume)419 void AudioStreamChecker::SetVolume(float volume)
420 {
421 std::lock_guard<std::mutex> lock(volumeLock_);
422 CHECK_AND_RETURN(curVolume_ != volume);
423 AUDIO_INFO_LOG("sessionId:%{public}u volume change from %{public}f to %{public}f",
424 streamConfig_.originalSessionId, curVolume_, volume);
425 curVolume_ = volume;
426 }
427 }
428 }
429