• 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 
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