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
16 #include "rs_frame_rate_vote.h"
17
18 #include <algorithm>
19
20 #include "hgm_core.h"
21 #include "platform/common/rs_log.h"
22 #include "rs_video_frame_rate_vote.h"
23 #include "sandbox_utils.h"
24
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28 const std::string VIDEO_RATE_FLAG = "VIDEO_RATE";
29 const std::string VIDEO_VOTE_FLAG = "VOTER_VIDEO";
30 // USE DURATION TO DETERMINE BARRAGE AND UI
31 constexpr uint64_t DANMU_MAX_INTERVAL_TIME = 50;
32 constexpr int32_t VIDEO_VOTE_DELAYS_TIME = 1000 * 1000;
33 }
34
RSFrameRateVote()35 RSFrameRateVote::RSFrameRateVote()
36 {
37 ffrtQueue_ = std::make_shared<ffrt::queue>("frame_rate_vote_queue");
38 auto policyConfigData = OHOS::Rosen::HgmCore::Instance().GetPolicyConfigData();
39 if (policyConfigData != nullptr) {
40 isSwitchOn_ = policyConfigData->videoFrameRateVoteSwitch_;
41 RS_LOGI("video vote feature isSwitchOn:%{public}s", isSwitchOn_ ? "true" : "false");
42 }
43 }
44
~RSFrameRateVote()45 RSFrameRateVote::~RSFrameRateVote()
46 {
47 ffrtQueue_ = nullptr;
48 }
49
SetTransactionFlags(const std::string & transactionFlags)50 void RSFrameRateVote::SetTransactionFlags(const std::string& transactionFlags)
51 {
52 std::lock_guard<std::mutex> lock(mutex_);
53 transactionFlags_ = transactionFlags;
54 }
55
CheckSurfaceAndUi()56 void RSFrameRateVote::CheckSurfaceAndUi()
57 {
58 if (!hasUiOrSurface) {
59 return;
60 }
61 hasUiOrSurface = false;
62 auto lastUpdateTime = currentUpdateTime_;
63 currentUpdateTime_ = OHOS::Rosen::HgmCore::Instance().GetActualTimestamp() / NS_PER_MS;
64 auto duration = currentUpdateTime_ > lastUpdateTime ? currentUpdateTime_ - lastUpdateTime : 0;
65 if (duration < DANMU_MAX_INTERVAL_TIME) {
66 if (lastVotedRate_ == OLED_NULL_HZ) {
67 return;
68 }
69 uint64_t currentId = lastSurfaceNodeId_.load();
70 {
71 std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
72 auto votingAddress = surfaceVideoFrameRateVote_.find(currentId);
73 if (votingAddress != surfaceVideoFrameRateVote_.end() && votingAddress->second) {
74 votingAddress->second->ReSetLastRate();
75 }
76 }
77 SurfaceVideoVote(currentId, 0);
78 }
79 }
80
VideoFrameRateVote(uint64_t surfaceNodeId,OHSurfaceSource sourceType,sptr<SurfaceBuffer> & buffer)81 void RSFrameRateVote::VideoFrameRateVote(uint64_t surfaceNodeId, OHSurfaceSource sourceType,
82 sptr<SurfaceBuffer>& buffer)
83 {
84 // transactionFlags_ format is [pid, eventId]
85 std::string transactionFlags = "";
86 std::string strLastVotedPid;
87 {
88 std::lock_guard<std::mutex> lock(mutex_);
89 transactionFlags = transactionFlags_;
90 strLastVotedPid = "[" + std::to_string(lastVotedPid_) + ",";
91 }
92 if (sourceType != OHSurfaceSource::OH_SURFACE_SOURCE_VIDEO ||
93 transactionFlags.find(strLastVotedPid) != std::string::npos) {
94 hasUiOrSurface = true;
95 }
96 // OH SURFACE SOURCE VIDEO AN UI VOTE
97 if (!isSwitchOn_ || sourceType != OHSurfaceSource::OH_SURFACE_SOURCE_VIDEO || buffer == nullptr) {
98 return;
99 }
100 double videoRate = 0.0;
101 sptr<BufferExtraData> extraData = buffer->GetExtraData();
102 if (extraData != nullptr) {
103 extraData->ExtraGet(VIDEO_RATE_FLAG, videoRate);
104 }
105 auto initTask = [this, surfaceNodeId, videoRate]() {
106 std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
107 std::shared_ptr<RSVideoFrameRateVote> rsVideoFrameRateVote;
108 if (surfaceVideoFrameRateVote_.find(surfaceNodeId) == surfaceVideoFrameRateVote_.end()) {
109 rsVideoFrameRateVote = std::make_shared<RSVideoFrameRateVote>(surfaceNodeId,
110 [this](uint64_t id) { this->ReleaseSurfaceMap(id); },
111 [this](uint64_t id, uint32_t rate) { this->SurfaceVideoVote(id, rate); });
112 surfaceVideoFrameRateVote_.insert(std::pair<uint64_t, std::shared_ptr<RSVideoFrameRateVote>>(
113 surfaceNodeId, rsVideoFrameRateVote));
114 } else {
115 rsVideoFrameRateVote = surfaceVideoFrameRateVote_[surfaceNodeId];
116 }
117 rsVideoFrameRateVote->StartVideoFrameRateVote(videoRate);
118 };
119 if (ffrtQueue_) {
120 ffrtQueue_->submit(initTask);
121 }
122 }
123
ReleaseSurfaceMap(uint64_t surfaceNodeId)124 void RSFrameRateVote::ReleaseSurfaceMap(uint64_t surfaceNodeId)
125 {
126 auto initTask = [this, surfaceNodeId]() {
127 SurfaceVideoVote(surfaceNodeId, 0);
128 std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
129 auto it = surfaceVideoFrameRateVote_.find(surfaceNodeId);
130 if (it != surfaceVideoFrameRateVote_.end()) {
131 RS_LOGI("video vote release surfaceNodeId(%{public}s), size(%{public}d)",
132 std::to_string(surfaceNodeId).c_str(), static_cast<int>(surfaceVideoFrameRateVote_.size()));
133 surfaceVideoFrameRateVote_.erase(it);
134 }
135 };
136 if (ffrtQueue_) {
137 ffrtQueue_->submit(initTask);
138 }
139 }
140
SurfaceVideoVote(uint64_t surfaceNodeId,uint32_t rate)141 void RSFrameRateVote::SurfaceVideoVote(uint64_t surfaceNodeId, uint32_t rate)
142 {
143 std::lock_guard<std::mutex> lock(mutex_);
144 if (rate == 0) {
145 auto it = surfaceVideoRate_.find(surfaceNodeId);
146 if (it != surfaceVideoRate_.end()) {
147 surfaceVideoRate_.erase(it);
148 }
149 } else {
150 surfaceVideoRate_[surfaceNodeId] = rate;
151 }
152 if (surfaceVideoRate_.size() == 0) {
153 CancelVoteRate(lastVotedPid_, VIDEO_VOTE_FLAG);
154 lastVotedPid_ = DEFAULT_PID;
155 lastVotedRate_ = OLED_NULL_HZ;
156 if (ffrtQueue_ && taskHandler_) {
157 ffrtQueue_->cancel(taskHandler_);
158 taskHandler_ = nullptr;
159 }
160 return;
161 }
162 auto maxElement = std::max_element(surfaceVideoRate_.begin(), surfaceVideoRate_.end(),
163 [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
164 uint32_t maxRate = maxElement->second;
165 pid_t maxPid = ExtractPid(maxElement->first);
166 lastSurfaceNodeId_ = maxElement->first;
167 if (maxRate == lastVotedRate_ && maxPid == lastVotedPid_) {
168 return;
169 }
170 CancelVoteRate(lastVotedPid_, VIDEO_VOTE_FLAG);
171 lastVotedPid_ = maxPid;
172 lastVotedRate_ = maxRate;
173 // Delay for one second to stabilize the voting
174 if (ffrtQueue_ && taskHandler_) {
175 ffrtQueue_->cancel(taskHandler_);
176 taskHandler_ = nullptr;
177 }
178 auto initTask = [this, maxPid, maxRate]() {
179 VoteRate(maxPid, VIDEO_VOTE_FLAG, maxRate);
180 };
181 ffrt::task_attr taskAttr;
182 taskAttr.delay(VIDEO_VOTE_DELAYS_TIME);
183 if (ffrtQueue_) {
184 taskHandler_ = ffrtQueue_->submit_h(initTask, taskAttr);
185 }
186 }
187
VoteRate(pid_t pid,std::string eventName,uint32_t rate)188 void RSFrameRateVote::VoteRate(pid_t pid, std::string eventName, uint32_t rate)
189 {
190 isVoted_ = true;
191 EventInfo eventInfo = {
192 .eventName = eventName,
193 .eventStatus = true,
194 .minRefreshRate = rate,
195 .maxRefreshRate = rate,
196 };
197 NotifyRefreshRateEvent(pid, eventInfo);
198 }
199
CancelVoteRate(pid_t pid,std::string eventName)200 void RSFrameRateVote::CancelVoteRate(pid_t pid, std::string eventName)
201 {
202 if (!isVoted_) {
203 return;
204 }
205 isVoted_ = false;
206 EventInfo eventInfo = {
207 .eventName = eventName,
208 .eventStatus = false,
209 };
210 NotifyRefreshRateEvent(pid, eventInfo);
211 }
212
NotifyRefreshRateEvent(pid_t pid,EventInfo eventInfo)213 void RSFrameRateVote::NotifyRefreshRateEvent(pid_t pid, EventInfo eventInfo)
214 {
215 if (pid > DEFAULT_PID) {
216 RS_LOGI("video vote pid:%{public}d rate(%{public}u, %{public}u)",
217 pid, eventInfo.minRefreshRate, eventInfo.maxRefreshRate);
218 HgmTaskHandleThread::Instance().PostTask([pid, eventInfo]() {
219 auto frameRateMgr = HgmCore::Instance().GetFrameRateMgr();
220 if (frameRateMgr != nullptr) {
221 frameRateMgr->HandleRefreshRateEvent(pid, eventInfo);
222 }
223 });
224 }
225 }
226 } // namespace Rosen
227 } // namespace OHOS