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