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
28 namespace OHOS {
29 namespace AudioStandard {
30
GetInstance()31 AudioPerformanceMonitor &AudioPerformanceMonitor::GetInstance()
32 {
33 static AudioPerformanceMonitor mgr;
34 return mgr;
35 }
36
RecordSilenceState(uint32_t sessionId,bool isSilence,AudioPipeType pipeType)37 void AudioPerformanceMonitor::RecordSilenceState(uint32_t sessionId, bool isSilence, AudioPipeType pipeType)
38 {
39 std::lock_guard<std::mutex> lock(silenceMapMutex_);
40 if (silenceDetectMap_.find(sessionId) == silenceDetectMap_.end()) {
41 CHECK_AND_RETURN_LOG(silenceDetectMap_.size() < MAX_MAP_SIZE, "silenceDetectMap_ overSize!");
42 AUDIO_INFO_LOG("start record silence state of sessionId : %{public}d", sessionId);
43 silenceDetectMap_[sessionId].silenceStateCount = MAX_SILENCE_FRAME_COUNT + 1;
44 silenceDetectMap_[sessionId].historyStateDeque.clear();
45 silenceDetectMap_[sessionId].pipeType = pipeType;
46 }
47 silenceDetectMap_[sessionId].historyStateDeque.push_back(isSilence);
48 if (silenceDetectMap_[sessionId].historyStateDeque.size() > MAX_RECORD_QUEUE_SIZE) {
49 silenceDetectMap_[sessionId].historyStateDeque.pop_front();
50 }
51 JudgeNoise(sessionId, isSilence);
52 }
53
ClearSilenceMonitor(uint32_t sessionId)54 void AudioPerformanceMonitor::ClearSilenceMonitor(uint32_t sessionId)
55 {
56 std::lock_guard<std::mutex> lock(silenceMapMutex_);
57 if (silenceDetectMap_.find(sessionId) == silenceDetectMap_.end()) {
58 return;
59 }
60 silenceDetectMap_[sessionId].silenceStateCount = MAX_SILENCE_FRAME_COUNT + 1;
61 silenceDetectMap_[sessionId].historyStateDeque.clear();
62 }
63
DeleteSilenceMonitor(uint32_t sessionId)64 void AudioPerformanceMonitor::DeleteSilenceMonitor(uint32_t sessionId)
65 {
66 std::lock_guard<std::mutex> lock(silenceMapMutex_);
67 CHECK_AND_RETURN_LOG(silenceDetectMap_.find(sessionId) != silenceDetectMap_.end(),
68 "invalid sessionId: %{public}d", sessionId);
69 AUDIO_INFO_LOG("delete sessionId %{public}d silence Monitor!", sessionId);
70 silenceDetectMap_.erase(sessionId);
71 }
72
RecordTimeStamp(AdapterType adapterType,int64_t curTimeStamp)73 void AudioPerformanceMonitor::RecordTimeStamp(AdapterType adapterType, int64_t curTimeStamp)
74 {
75 std::lock_guard<std::mutex> lock(overTimeMapMutex_);
76 CHECK_AND_RETURN_LOG(adapterType > AdapterType::ADAPTER_TYPE_UNKNOWN &&
77 adapterType < AdapterType::ADAPTER_TYPE_MAX, "invalid adapterType: %{public}d", adapterType);
78 if (overTimeDetectMap_.find(adapterType) == overTimeDetectMap_.end()) {
79 CHECK_AND_RETURN_LOG(overTimeDetectMap_.size() < MAX_MAP_SIZE, "overTimeDetectMap_ overSize!");
80 AUDIO_INFO_LOG("start record adapterType: %{public}d", adapterType);
81 overTimeDetectMap_[adapterType] = curTimeStamp;
82 return;
83 }
84
85 // init lastwritten time when start or resume to avoid overtime
86 if (curTimeStamp == INIT_LASTWRITTEN_TIME || overTimeDetectMap_[adapterType] == INIT_LASTWRITTEN_TIME) {
87 overTimeDetectMap_[adapterType] = curTimeStamp;
88 return;
89 }
90
91 if (curTimeStamp - overTimeDetectMap_[adapterType] > MAX_WRITTEN_INTERVAL[adapterType]) {
92 int64_t rawOvertimeMs = (curTimeStamp - overTimeDetectMap_[adapterType]) / AUDIO_NS_PER_MS;
93 int32_t overtimeMs = static_cast<int32_t>(rawOvertimeMs < 0 ? 0 :
94 (rawOvertimeMs >= INT32_MAX ? INT32_MAX : rawOvertimeMs));
95 AUDIO_WARNING_LOG("AdapterType %{public}d, PipeType %{public}d, write time interval %{public}d ms! overTime!",
96 adapterType, PIPE_TYPE_MAP[adapterType], overtimeMs);
97 ReportEvent(OVERTIME_EVENT, overtimeMs, PIPE_TYPE_MAP[adapterType], adapterType);
98 }
99 overTimeDetectMap_[adapterType] = curTimeStamp;
100 }
101
DeleteOvertimeMonitor(AdapterType adapterType)102 void AudioPerformanceMonitor::DeleteOvertimeMonitor(AdapterType adapterType)
103 {
104 std::lock_guard<std::mutex> lock(overTimeMapMutex_);
105 CHECK_AND_RETURN_LOG(overTimeDetectMap_.find(adapterType) != overTimeDetectMap_.end(),
106 "invalid adapterType: %{public}d", adapterType);
107 AUDIO_INFO_LOG("delete adapterType %{public}d overTime Monitor!", adapterType);
108 overTimeDetectMap_.erase(adapterType);
109 }
110
DumpMonitorInfo(std::string & dumpString)111 void AudioPerformanceMonitor::DumpMonitorInfo(std::string &dumpString)
112 {
113 std::lock_guard<std::mutex> lock1(silenceMapMutex_);
114 std::lock_guard<std::mutex> lock2(overTimeMapMutex_);
115 dumpString += "\n----------silenceMonitor----------\n";
116 dumpString += "streamId\tcountNum\tcurState\n";
117 for (auto it = silenceDetectMap_.begin(); it != silenceDetectMap_.end(); ++it) {
118 dumpString += std::to_string(it->first) + "\t\t" + std::to_string(it->second.silenceStateCount) + "\t\t";
119 for (auto cit = it->second.historyStateDeque.begin(); cit != it->second.historyStateDeque.end(); ++cit) {
120 dumpString += (*cit) ? "_" : "-";
121 }
122 dumpString += "\n";
123 }
124 dumpString += "\nLastSilenceReportTime: " +
125 (silenceLastReportTime_ == INIT_LASTWRITTEN_TIME ?
126 "not report yet" : ClockTime::NanoTimeToString(silenceLastReportTime_));
127
128 dumpString += "\n\n----------overTimeMonitor----------\n";
129 dumpString += "adapterType\tlastWrittenTime\n";
130 for (auto it = overTimeDetectMap_.begin(); it != overTimeDetectMap_.end(); ++it) {
131 dumpString += std::to_string(it->first) + "\t\t" + std::to_string(it->second) + "\n";
132 }
133 dumpString += "\nLastOverTimeReportTime: " +
134 (overTimeLastReportTime_ == INIT_LASTWRITTEN_TIME ?
135 "not report yet" : ClockTime::NanoTimeToString(overTimeLastReportTime_));
136 }
137
138 // we use silenceStateCount to record the silence frames bewteen two not silence frame
139 // need to check if sessionId exists before use
JudgeNoise(uint32_t sessionId,bool isSilence)140 void AudioPerformanceMonitor::JudgeNoise(uint32_t sessionId, bool isSilence)
141 {
142 if (isSilence) {
143 silenceDetectMap_[sessionId].silenceStateCount++;
144 } else {
145 // we init the count value as the maxValue+1 to make it as normal state
146 if (MIN_SILENCE_FRAME_COUNT <= silenceDetectMap_[sessionId].silenceStateCount &&
147 silenceDetectMap_[sessionId].silenceStateCount <= MAX_SILENCE_FRAME_COUNT) {
148 std::string printStr{};
149 // for example: not Silent-> not Silent -> silent -> not Silent -> silent, will print "--_-_"
150 while (silenceDetectMap_[sessionId].historyStateDeque.size() != 0) {
151 printStr += silenceDetectMap_[sessionId].historyStateDeque.front() ? "_" : "-";
152 silenceDetectMap_[sessionId].historyStateDeque.pop_front();
153 }
154 AUDIO_WARNING_LOG("record %{public}d state, pipeType %{public}d for last %{public}zu times: %{public}s",
155 sessionId, silenceDetectMap_[sessionId].pipeType, MAX_RECORD_QUEUE_SIZE, printStr.c_str());
156 ReportEvent(SILENCE_EVENT, INT32_MAX, silenceDetectMap_[sessionId].pipeType, ADAPTER_TYPE_UNKNOWN);
157 silenceDetectMap_[sessionId].silenceStateCount = MAX_SILENCE_FRAME_COUNT + 1;
158 silenceDetectMap_[sessionId].historyStateDeque.clear();
159 return;
160 }
161 silenceDetectMap_[sessionId].silenceStateCount = 0;
162 }
163 }
164
ReportEvent(DetectEvent reasonCode,int32_t periodMs,AudioPipeType pipeType,AdapterType adapterType)165 void AudioPerformanceMonitor::ReportEvent(DetectEvent reasonCode, int32_t periodMs, AudioPipeType pipeType,
166 AdapterType adapterType)
167 {
168 int64_t curRealTime = ClockTime::GetRealNano();
169 switch (reasonCode) {
170 case SILENCE_EVENT:
171 CHECK_AND_RETURN_LOG(curRealTime - silenceLastReportTime_ >= MIN_REPORT_INTERVAL_MS * AUDIO_NS_PER_MS,
172 "report silence event too frequent!");
173 silenceLastReportTime_ = ClockTime::GetRealNano();
174 break;
175 case OVERTIME_EVENT:
176 CHECK_AND_RETURN_LOG(curRealTime - overTimeLastReportTime_ >= MIN_REPORT_INTERVAL_MS * AUDIO_NS_PER_MS,
177 "report overtime event too frequent!");
178 overTimeLastReportTime_ = ClockTime::GetRealNano();
179 break;
180 default:
181 AUDIO_ERR_LOG("invalid DetectEvent %{public}d", reasonCode);
182 return;
183 }
184 #ifndef AUDIO_BUILD_VARIANT_ROOT
185 AUDIO_WARNING_LOG("report reasonCode %{public}d", reasonCode);
186 std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
187 Media::MediaMonitor::AUDIO, Media::MediaMonitor::EventId::JANK_PLAYBACK,
188 Media::MediaMonitor::EventType::FAULT_EVENT);
189 bean->Add("REASON", reasonCode);
190 bean->Add("PERIOD_MS", periodMs);
191 bean->Add("PIPE_TYPE", pipeType);
192 bean->Add("HDI_ADAPTER", adapterType);
193 Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
194 #endif
195 }
196
197 } // namespace AudioStandard
198 } // namespace OHOS
199
200 #ifdef __cplusplus
201 extern "C" {
202 #endif
203
204 using namespace OHOS::AudioStandard;
205
RecordPaSilenceState(uint32_t sessionId,bool isSilence,enum PA_PIPE_TYPE paPipeType)206 void RecordPaSilenceState(uint32_t sessionId, bool isSilence, enum PA_PIPE_TYPE paPipeType)
207 {
208 switch (paPipeType) {
209 case PA_PIPE_TYPE_NORMAL:
210 AudioPerformanceMonitor::GetInstance().RecordSilenceState(sessionId, isSilence, PIPE_TYPE_NORMAL_OUT);
211 break;
212 case PA_PIPE_TYPE_MULTICHANNEL:
213 AudioPerformanceMonitor::GetInstance().RecordSilenceState(sessionId, isSilence, PIPE_TYPE_MULTICHANNEL);
214 default:
215 break;
216 }
217 }
218
219 #ifdef __cplusplus
220 }
221 #endif
222