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