• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "AudioPerformanceMonitor"
17 #endif
18 
19 #include "audio_performance_monitor.h"
20 #include "audio_performance_monitor_c.h"
21 #include <memory>
22 #include <string>
23 #include "audio_errors.h"
24 #include "media_monitor_manager.h"
25 #include "audio_common_log.h"
26 #include "audio_utils.h"
27 #include "audio_utils_c.h"
28 
29 namespace OHOS {
30 namespace AudioStandard {
31 namespace {
32 const int32_t FAST_DURATION_MS = 5; // 5ms
33 const int32_t NORMAL_DURAION_MS = 20; // 20ms
34 }
35 
GetInstance()36 AudioPerformanceMonitor &AudioPerformanceMonitor::GetInstance()
37 {
38     static AudioPerformanceMonitor mgr;
39     return mgr;
40 }
41 
RecordSilenceState(uint32_t sessionId,bool isSilence,AudioPipeType pipeType,uint32_t uid)42 void AudioPerformanceMonitor::RecordSilenceState(uint32_t sessionId, bool isSilence, AudioPipeType pipeType,
43     uint32_t uid)
44 {
45     std::lock_guard<std::mutex> lock(monitorMutex_);
46     if (silenceDetectMap_.find(sessionId) == silenceDetectMap_.end()) {
47         CHECK_AND_RETURN_LOG(silenceDetectMap_.size() < MAX_MAP_SIZE, "silenceDetectMap_ overSize!");
48         AUDIO_INFO_LOG("start record silence state of sessionId : %{public}d", sessionId);
49         silenceDetectMap_[sessionId].silenceStateCount = MAX_SILENCE_FRAME_COUNT + 1;
50         silenceDetectMap_[sessionId].historyStateDeque.clear();
51     }
52     silenceDetectMap_[sessionId].pipeType = pipeType; // update pipeType info
53     silenceDetectMap_[sessionId].historyStateDeque.push_back(isSilence);
54     if (silenceDetectMap_[sessionId].historyStateDeque.size() > MAX_RECORD_QUEUE_SIZE) {
55         silenceDetectMap_[sessionId].historyStateDeque.pop_front();
56     }
57     JudgeNoise(sessionId, isSilence, uid);
58 }
59 
StartSilenceMonitor(uint32_t sessionId,uint32_t tokenId)60 void AudioPerformanceMonitor::StartSilenceMonitor(uint32_t sessionId, uint32_t tokenId)
61 {
62     std::lock_guard<std::mutex> lock(monitorMutex_);
63     if (silenceDetectMap_.find(sessionId) == silenceDetectMap_.end()) {
64         CHECK_AND_RETURN_LOG(silenceDetectMap_.size() < MAX_MAP_SIZE, "silenceDetectMap_ overSize!");
65         AUDIO_INFO_LOG("start record silence state of sessionId : %{public}d", sessionId);
66     }
67     silenceDetectMap_[sessionId].silenceStateCount = MAX_SILENCE_FRAME_COUNT + 1;
68     silenceDetectMap_[sessionId].historyStateDeque.clear();
69     silenceDetectMap_[sessionId].tokenId = tokenId; // record tokenId to get bundle name
70     silenceDetectMap_[sessionId].isRunning = true;
71 }
72 
PauseSilenceMonitor(uint32_t sessionId)73 void AudioPerformanceMonitor::PauseSilenceMonitor(uint32_t sessionId)
74 {
75     std::lock_guard<std::mutex> lock(monitorMutex_);
76     if (silenceDetectMap_.find(sessionId) == silenceDetectMap_.end()) {
77         return;
78     }
79     silenceDetectMap_[sessionId].isRunning = false;
80 }
81 
DeleteSilenceMonitor(uint32_t sessionId)82 void AudioPerformanceMonitor::DeleteSilenceMonitor(uint32_t sessionId)
83 {
84     std::lock_guard<std::mutex> lock(monitorMutex_);
85     CHECK_AND_RETURN_LOG(silenceDetectMap_.find(sessionId) != silenceDetectMap_.end(),
86         "invalid sessionId: %{public}d", sessionId);
87     AUDIO_INFO_LOG("delete sessionId %{public}d silence Monitor!", sessionId);
88     silenceDetectMap_.erase(sessionId);
89 }
90 
ReportWriteSlow(AdapterType adapterType,int32_t overtimeMs)91 void AudioPerformanceMonitor::ReportWriteSlow(AdapterType adapterType, int32_t overtimeMs)
92 {
93     std::lock_guard<std::mutex> lock(monitorMutex_);
94     AUDIO_WARNING_LOG("AdapterType %{public}d, PipeType %{public}d, write time interval %{public}d ms! overTime!",
95         adapterType, PIPE_TYPE_MAP[adapterType], overtimeMs);
96     AUTO_CTRACE("Fast pipe OVERTIME_EVENT, overtimeMs: %d, pipeType %d, adapterType: %d", overtimeMs,
97         PIPE_TYPE_MAP[adapterType], adapterType);
98     ReportEvent(OVERTIME_EVENT, overtimeMs, PIPE_TYPE_MAP[adapterType], adapterType);
99 }
100 
RecordTimeStamp(AdapterType adapterType,int64_t curTimeStamp)101 void AudioPerformanceMonitor::RecordTimeStamp(AdapterType adapterType, int64_t curTimeStamp)
102 {
103     std::lock_guard<std::mutex> lock(monitorMutex_);
104     CHECK_AND_RETURN_LOG(adapterType > AdapterType::ADAPTER_TYPE_UNKNOWN &&
105         adapterType < AdapterType::ADAPTER_TYPE_MAX, "invalid adapterType: %{public}d", adapterType);
106     if (overTimeDetectMap_.find(adapterType) == overTimeDetectMap_.end()) {
107         CHECK_AND_RETURN_LOG(overTimeDetectMap_.size() < MAX_MAP_SIZE, "overTimeDetectMap_ overSize!");
108         AUDIO_INFO_LOG("start record adapterType: %{public}d", adapterType);
109         overTimeDetectMap_[adapterType] = curTimeStamp;
110         return;
111     }
112 
113     // init lastwritten time when start or resume to avoid overtime
114     if (curTimeStamp == INIT_LASTWRITTEN_TIME || overTimeDetectMap_[adapterType] == INIT_LASTWRITTEN_TIME) {
115         overTimeDetectMap_[adapterType] = curTimeStamp;
116         return;
117     }
118 
119     if (curTimeStamp - overTimeDetectMap_[adapterType] > MAX_WRITTEN_INTERVAL[adapterType]) {
120         int64_t rawOvertimeMs = (curTimeStamp - overTimeDetectMap_[adapterType]) / AUDIO_NS_PER_MS;
121         int32_t overtimeMs = static_cast<int32_t>(rawOvertimeMs < 0 ? 0 :
122             (rawOvertimeMs >= INT32_MAX ? INT32_MAX : rawOvertimeMs));
123         AUDIO_WARNING_LOG("AdapterType %{public}d, PipeType %{public}d, write time interval %{public}d ms! overTime!",
124             adapterType, PIPE_TYPE_MAP[adapterType], overtimeMs);
125         AUTO_CTRACE("Audio HAL detect OVERTIME_EVENT, overtimeMs: %d, pipeType %d, adapterType: %d",
126             overtimeMs, PIPE_TYPE_MAP[adapterType], adapterType);
127         ReportEvent(OVERTIME_EVENT, overtimeMs, PIPE_TYPE_MAP[adapterType], adapterType);
128     }
129     overTimeDetectMap_[adapterType] = curTimeStamp;
130 }
131 
DeleteOvertimeMonitor(AdapterType adapterType)132 void AudioPerformanceMonitor::DeleteOvertimeMonitor(AdapterType adapterType)
133 {
134     std::lock_guard<std::mutex> lock(monitorMutex_);
135     CHECK_AND_RETURN_LOG(overTimeDetectMap_.find(adapterType) != overTimeDetectMap_.end(),
136         "invalid adapterType: %{public}d", adapterType);
137     AUDIO_INFO_LOG("delete adapterType %{public}d overTime Monitor!", adapterType);
138     overTimeDetectMap_.erase(adapterType);
139 }
140 
DumpMonitorInfo(std::string & dumpString)141 void AudioPerformanceMonitor::DumpMonitorInfo(std::string &dumpString)
142 {
143     std::lock_guard<std::mutex> lock(monitorMutex_);
144     dumpString += "\n----------silenceMonitor----------\n";
145     dumpString += "streamId\tcountNum\tcurState\n";
146     for (auto it = silenceDetectMap_.begin(); it != silenceDetectMap_.end(); ++it) {
147         dumpString += std::to_string(it->first) + "\t\t" + std::to_string(it->second.silenceStateCount) + "\t\t";
148         for (auto cit = it->second.historyStateDeque.begin(); cit != it->second.historyStateDeque.end(); ++cit) {
149             dumpString += (*cit) ? "_" : "-";
150         }
151         dumpString += "\n";
152     }
153     dumpString += "\nLastSilenceReportTime: " +
154         (silenceLastReportTime_ == INIT_LASTWRITTEN_TIME ?
155             "not report yet" : ClockTime::NanoTimeToString(silenceLastReportTime_));
156 
157     dumpString += "\n\n----------overTimeMonitor----------\n";
158     dumpString += "adapterType\tlastWrittenTime\n";
159     for (auto it = overTimeDetectMap_.begin(); it != overTimeDetectMap_.end(); ++it) {
160         dumpString += std::to_string(it->first) + "\t\t" + std::to_string(it->second) + "\n";
161     }
162     dumpString += "\nLastOverTimeReportTime: " +
163         (overTimeLastReportTime_ == INIT_LASTWRITTEN_TIME ?
164             "not report yet" : ClockTime::NanoTimeToString(overTimeLastReportTime_));
165 }
166 
167 // we use silenceStateCount to record the silence frames bewteen two not silence frame
168 // need to check if sessionId exists before use
JudgeNoise(uint32_t sessionId,bool isSilence,uint32_t uid)169 void AudioPerformanceMonitor::JudgeNoise(uint32_t sessionId, bool isSilence, uint32_t uid)
170 {
171     if (isSilence) {
172         silenceDetectMap_[sessionId].silenceStateCount++;
173     } else {
174         // we init the count value as the maxValue+1 to make it as normal state
175         if (MIN_SILENCE_FRAME_COUNT <= silenceDetectMap_[sessionId].silenceStateCount &&
176             silenceDetectMap_[sessionId].silenceStateCount <= MAX_SILENCE_FRAME_COUNT) {
177             std::string printStr{};
178             // for example: not Silent-> not Silent -> silent -> not Silent -> silent, will print "--_-_"
179             while (silenceDetectMap_[sessionId].historyStateDeque.size() != 0) {
180                 printStr += silenceDetectMap_[sessionId].historyStateDeque.front() ? "_" : "-";
181                 silenceDetectMap_[sessionId].historyStateDeque.pop_front();
182             }
183             AUDIO_WARNING_LOG("record %{public}d state, pipeType %{public}d for last %{public}zu times: %{public}s",
184                 sessionId, silenceDetectMap_[sessionId].pipeType, MAX_RECORD_QUEUE_SIZE, printStr.c_str());
185             AUTO_CTRACE("Audio FWK detect SILENCE_EVENT, pipeType %d, PreState: %s",
186                 silenceDetectMap_[sessionId].pipeType, printStr.c_str());
187             AudioPipeType pipeType = silenceDetectMap_[sessionId].pipeType;
188             int32_t periodMs = static_cast<int32_t>(silenceDetectMap_[sessionId].silenceStateCount *
189                 (pipeType == PIPE_TYPE_LOWLATENCY_OUT ? FAST_DURATION_MS : NORMAL_DURAION_MS));
190             ReportEvent(SILENCE_EVENT, periodMs, pipeType, ADAPTER_TYPE_UNKNOWN, uid);
191             silenceDetectMap_[sessionId].silenceStateCount = MAX_SILENCE_FRAME_COUNT + 1;
192             silenceDetectMap_[sessionId].historyStateDeque.clear();
193             return;
194         }
195         silenceDetectMap_[sessionId].silenceStateCount = 0;
196     }
197 }
198 
GetRunningHapNames(AdapterType adapterType)199 std::string AudioPerformanceMonitor::GetRunningHapNames(AdapterType adapterType)
200 {
201     // eg. com.test.hap1;com.test.hap2;
202     WatchTimeout guard("GetRunningHapNames");
203     std::stringstream hapNames;
204     AudioPipeType pipeType = PIPE_TYPE_MAP[adapterType];
205     for (auto item : silenceDetectMap_) {
206         if (item.second.isRunning && item.second.pipeType == pipeType) {
207             std::string name = GetBundleNameByToken(item.second.tokenId);
208             hapNames << name << ";";
209         }
210     }
211     return hapNames.str();
212 }
213 
ReportEvent(DetectEvent reasonCode,int32_t periodMs,AudioPipeType pipeType,AdapterType adapterType,uint32_t uid)214 void AudioPerformanceMonitor::ReportEvent(DetectEvent reasonCode, int32_t periodMs, AudioPipeType pipeType,
215     AdapterType adapterType, uint32_t uid)
216 {
217     int64_t curRealTime = ClockTime::GetRealNano();
218     std::string hapNames = "";
219     switch (reasonCode) {
220         case SILENCE_EVENT:
221             CHECK_AND_RETURN_LOG(curRealTime - silenceLastReportTime_ >= MIN_REPORT_INTERVAL_MS * AUDIO_NS_PER_MS,
222                 "report silence event too frequent!");
223             silenceLastReportTime_ = ClockTime::GetRealNano();
224             break;
225         case OVERTIME_EVENT:
226             CHECK_AND_RETURN_LOG(curRealTime - overTimeLastReportTime_ >= MIN_REPORT_INTERVAL_MS * AUDIO_NS_PER_MS,
227                 "report overtime event too frequent!");
228             overTimeLastReportTime_ = ClockTime::GetRealNano();
229             hapNames = GetRunningHapNames(adapterType);
230             break;
231         default:
232             AUDIO_ERR_LOG("invalid DetectEvent %{public}d", reasonCode);
233             return;
234     }
235 #ifndef AUDIO_BUILD_VARIANT_ROOT
236     AUDIO_WARNING_LOG("report reasonCode %{public}d for uid:%{public}d", reasonCode, uid);
237     std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
238         Media::MediaMonitor::AUDIO, Media::MediaMonitor::EventId::JANK_PLAYBACK,
239         Media::MediaMonitor::EventType::FAULT_EVENT);
240     bean->Add("REASON", reasonCode);
241     bean->Add("PERIOD_MS", periodMs);
242     bean->Add("PIPE_TYPE", pipeType);
243     bean->Add("HDI_ADAPTER", adapterType);
244     bean->Add("POSITION", JANK_POSITON_CODE);
245     bean->Add("UID", static_cast<int32_t>(uid));
246     if (reasonCode == OVERTIME_EVENT) {
247         bean->Add("APP_NAMES", hapNames);
248     }
249     int64_t jankStartTime = curRealTime / AUDIO_NS_PER_MILLISECOND - static_cast<int64_t>(periodMs);
250     bean->Add("JANK_START_TIME", static_cast<uint64_t>(jankStartTime));
251     Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
252 #endif
253 }
254 
255 } // namespace AudioStandard
256 } // namespace OHOS
257 
258 #ifdef __cplusplus
259 extern "C" {
260 #endif
261 
262 using namespace OHOS::AudioStandard;
263 
RecordPaSilenceState(uint32_t sessionId,bool isSilence,enum PA_PIPE_TYPE paPipeType,uint32_t uid)264 void RecordPaSilenceState(uint32_t sessionId, bool isSilence, enum PA_PIPE_TYPE paPipeType, uint32_t uid)
265 {
266     switch (paPipeType) {
267         case PA_PIPE_TYPE_NORMAL:
268             AudioPerformanceMonitor::GetInstance().RecordSilenceState(sessionId, isSilence, PIPE_TYPE_NORMAL_OUT, uid);
269             break;
270         case PA_PIPE_TYPE_MULTICHANNEL:
271             AudioPerformanceMonitor::GetInstance().RecordSilenceState(sessionId, isSilence, PIPE_TYPE_MULTICHANNEL,
272                 uid);
273             break;
274         default:
275             break;
276     }
277 }
278 
279 #ifdef __cplusplus
280 }
281 #endif
282