1 /*
2 * Copyright (c) 2023 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 #include "ifeeding_smoother.h"
16 #include "distributed_camera_constants.h"
17 #include <sys/prctl.h>
18 #include "dcamera_utils_tools.h"
19 #include <cstdlib>
20 #include "distributed_hardware_log.h"
21 #include "smoother_constants.h"
22
23 namespace OHOS {
24 namespace DistributedHardware {
~IFeedingSmoother()25 IFeedingSmoother::~IFeedingSmoother()
26 {
27 std::lock_guard<std::mutex> lock(stateMutex_);
28 if (state_ == SMOOTH_START) {
29 StopSmooth();
30 }
31 }
32
PushData(const std::shared_ptr<IFeedableData> & data)33 void IFeedingSmoother::PushData(const std::shared_ptr<IFeedableData>& data)
34 {
35 {
36 std::lock_guard<std::mutex> lock(stateMutex_);
37 if (state_ == SMOOTH_STOP) {
38 DHLOGD("Smoother stop, push data failed.");
39 return;
40 }
41 }
42 {
43 std::lock_guard<std::mutex> lock(queueMutex_);
44 dataQueue_.push(data);
45 }
46 if (statistician_ != nullptr) {
47 statistician_->CalProcessTime(data);
48 }
49 smoothCon_.notify_one();
50 }
51
StartSmooth()52 int32_t IFeedingSmoother::StartSmooth()
53 {
54 {
55 std::lock_guard<std::mutex> lock(stateMutex_);
56 if (state_ == SMOOTH_START) {
57 DHLOGD("Smoother is started.");
58 return SMOOTH_IS_STARTED;
59 }
60 state_ = SMOOTH_START;
61 }
62 InitTimeStatistician();
63 PrepareSmooth();
64 smoothThread_ = std::thread([this]() { this->LooperSmooth(); });
65 return SMOOTH_SUCCESS;
66 }
67
LooperSmooth()68 void IFeedingSmoother::LooperSmooth()
69 {
70 prctl(PR_SET_NAME, LOOPER_SMOOTH.c_str());
71 while (state_ == SMOOTH_START) {
72 std::shared_ptr<IFeedableData> data = nullptr;
73 {
74 std::unique_lock<std::mutex> lock(queueMutex_);
75 smoothCon_.wait(lock, [this] {
76 return (!dataQueue_.empty() || this->state_ == SMOOTH_STOP);
77 });
78 if (state_ == SMOOTH_STOP) {
79 continue;
80 }
81 data = dataQueue_.front();
82 }
83 SmoothFeeding(data);
84 int32_t ret = NotifySmoothFinished(data);
85 if (ret == NOTIFY_FAILED) {
86 DHLOGD("Smoother listener notify producer failed.");
87 return;
88 }
89 {
90 std::lock_guard<std::mutex> lock(queueMutex_);
91 dataQueue_.pop();
92 }
93 }
94 }
95
SmoothFeeding(const std::shared_ptr<IFeedableData> & data)96 void IFeedingSmoother::SmoothFeeding(const std::shared_ptr<IFeedableData>& data)
97 {
98 CHECK_AND_RETURN_LOG(data == nullptr, "data is nullptr");
99 int64_t enterTime = GetNowTimeStampUs();
100 SetClockTime(enterTime);
101 int64_t timeStamp = data->GetTimeStamp();
102 if (timeStamp == 0) {
103 return;
104 }
105 if (!CheckIsProcessInDynamicBalance() || !CheckIsTimeInit()) {
106 RecordTime(enterTime, timeStamp);
107 return;
108 }
109
110 if (!CheckIsBaselineInit()) {
111 InitBaseline(timeStamp, clockTime_);
112 }
113 int64_t interval = timeStamp - lastTimeStamp_;
114 int64_t elapse = enterTime - leaveTime_;
115 int64_t render = enterTime - lastEnterTime_;
116 int64_t delta = render - sleep_ - elapse;
117 delta_ += delta;
118 int64_t clock = timeStampBaseline_ + clockTime_ - clockBaseline_;
119 sleep_ = interval - elapse;
120 AdjustSleepTime(interval);
121 SyncClock(timeStamp, interval, clock);
122 {
123 std::unique_lock<std::mutex> lock(sleepMutex_);
124 sleepCon_.wait_for(lock, std::chrono::microseconds(sleep_), [this] {
125 return (this->state_ == SMOOTH_STOP);
126 });
127 if (state_ == SMOOTH_STOP) {
128 DHLOGD("Notify to interrupt sleep.");
129 return;
130 }
131 }
132 RecordTime(enterTime, timeStamp);
133 }
134
CheckIsProcessInDynamicBalance()135 bool IFeedingSmoother::CheckIsProcessInDynamicBalance()
136 {
137 if (isInDynamicBalance_.load()) {
138 return true;
139 }
140 if (CheckIsProcessInDynamicBalanceOnce()) {
141 dynamicBalanceCount_++;
142 } else {
143 dynamicBalanceCount_ = 0;
144 }
145 if (dynamicBalanceCount_ >= dynamicBalanceThre_) {
146 isInDynamicBalance_.store(true);
147 return true;
148 }
149 return false;
150 }
151
CheckIsProcessInDynamicBalanceOnce()152 bool IFeedingSmoother::CheckIsProcessInDynamicBalanceOnce()
153 {
154 if (statistician_ == nullptr) {
155 return false;
156 }
157 int64_t feedInterval = statistician_->GetFeedInterval();
158 int64_t averFeedInterval = statistician_->GetAverFeedInterval();
159 int64_t averTimeStamapInterval = statistician_->GetAverTimeStampInterval();
160 int64_t averIntervalDiff = averFeedInterval - averTimeStamapInterval;
161 int64_t feedOnceDiff = feedInterval - averFeedInterval;
162 return (averFeedInterval != 0) && (averTimeStamapInterval != 0) &&
163 (llabs(averIntervalDiff) < averIntervalDiffThre_) && (llabs(feedOnceDiff) < feedOnceDiffThre_);
164 }
165
CheckIsBaselineInit()166 bool IFeedingSmoother::CheckIsBaselineInit()
167 {
168 return isBaselineInit_.load();
169 }
170
CheckIsTimeInit()171 bool IFeedingSmoother::CheckIsTimeInit()
172 {
173 return isTimeInit_.load();
174 }
175
InitBaseline(const int64_t timeStampBaseline,const int64_t clockBaseline)176 void IFeedingSmoother::InitBaseline(const int64_t timeStampBaseline, const int64_t clockBaseline)
177 {
178 SetTimeStampBaseline(timeStampBaseline);
179 SetClockBaseline(clockBaseline + bufferTime_);
180 isBaselineInit_.store(true);
181 }
182
NotifySmoothFinished(const std::shared_ptr<IFeedableData> & data)183 int32_t IFeedingSmoother::NotifySmoothFinished(const std::shared_ptr<IFeedableData>& data)
184 {
185 if (listener_ == nullptr) {
186 DHLOGE("Smoother listener is nullptr.");
187 return NOTIFY_FAILED;
188 }
189 return listener_->OnSmoothFinished(data);
190 }
191
AdjustSleepTime(const int64_t interval)192 void IFeedingSmoother::AdjustSleepTime(const int64_t interval)
193 {
194 const int64_t adjustThre = interval * adjustSleepFactor_;
195 if (delta_ > adjustThre && sleep_ > 0) {
196 int64_t sleep = sleep_ - adjustThre;
197 delta_ -= (sleep < 0) ? sleep_ : adjustThre;
198 sleep_ = sleep;
199 DHLOGD("Delta more than thre, adjust sleep to %{public}" PRId64" us.", sleep_);
200 } else if (delta_ < -adjustThre) {
201 sleep_ += delta_;
202 delta_ = 0;
203 DHLOGD("Delta less than negative thre, adjust sleep to %{public}" PRId64" us.", sleep_);
204 }
205 }
206
SyncClock(const int64_t timeStamp,const int64_t interval,const int64_t clock)207 void IFeedingSmoother::SyncClock(const int64_t timeStamp, const int64_t interval, const int64_t clock)
208 {
209 const int64_t waitThre = interval * waitClockFactor_;
210 const int64_t trackThre = interval * trackClockFactor_;
211 int64_t offset = timeStamp - sleep_ - clock;
212 if (offset > waitThre || offset < -trackThre) {
213 sleep_ += offset;
214 DHLOGD("Offset is not in the threshold range, adjust sleep to %{public}" PRId64" us.", sleep_);
215 }
216 if (sleep_ < 0) {
217 sleep_ = 0;
218 DHLOGD("Sleep less than zero, adjust sleep to zero.");
219 }
220 DHLOGD("Offset is %{public}" PRId64" us, sleep is %{public}" PRId64" us after syncing clock.", offset, sleep_);
221 }
222
RecordTime(const int64_t enterTime,const int64_t timeStamp)223 void IFeedingSmoother::RecordTime(const int64_t enterTime, const int64_t timeStamp)
224 {
225 lastEnterTime_ = enterTime;
226 lastTimeStamp_ = timeStamp;
227 leaveTime_ = GetNowTimeStampUs();
228 isTimeInit_.store(true);
229 }
230
StopSmooth()231 int32_t IFeedingSmoother::StopSmooth()
232 {
233 {
234 std::lock_guard<std::mutex> lock(stateMutex_);
235 if (state_ == SMOOTH_STOP) {
236 DHLOGD("Smooth is stoped.");
237 return SMOOTH_IS_STOPED;
238 }
239 state_ = SMOOTH_STOP;
240 }
241 smoothCon_.notify_one();
242 sleepCon_.notify_one();
243 if (smoothThread_.joinable()) {
244 smoothThread_.join();
245 }
246 statistician_ = nullptr;
247 UnregisterListener();
248
249 std::queue<std::shared_ptr<IFeedableData>>().swap(dataQueue_);
250 DHLOGD("Stop smooth success.");
251 return SMOOTH_SUCCESS;
252 }
253
InitTimeStatistician()254 void IFeedingSmoother::InitTimeStatistician()
255 {
256 if (statistician_ != nullptr) {
257 return;
258 }
259 statistician_ = std::make_shared<TimeStatistician>();
260 }
261
RegisterListener(const std::shared_ptr<FeedingSmootherListener> & listener)262 void IFeedingSmoother::RegisterListener(const std::shared_ptr<FeedingSmootherListener>& listener)
263 {
264 listener_ = listener;
265 }
266
UnregisterListener()267 void IFeedingSmoother::UnregisterListener()
268 {
269 listener_ = nullptr;
270 }
271
SetBufferTime(const int32_t time)272 void IFeedingSmoother::SetBufferTime(const int32_t time)
273 {
274 bufferTime_ = time;
275 }
276
SetDynamicBalanceThre(const uint8_t thre)277 void IFeedingSmoother::SetDynamicBalanceThre(const uint8_t thre)
278 {
279 dynamicBalanceThre_ = thre;
280 }
281
SetProcessDynamicBalanceState(const bool state)282 void IFeedingSmoother::SetProcessDynamicBalanceState(const bool state)
283 {
284 isInDynamicBalance_.store(state);
285 }
286
SetAverIntervalDiffThre(const uint32_t thre)287 void IFeedingSmoother::SetAverIntervalDiffThre(const uint32_t thre)
288 {
289 averIntervalDiffThre_ = thre;
290 }
291
SetFeedOnceDiffThre(const uint32_t thre)292 void IFeedingSmoother::SetFeedOnceDiffThre(const uint32_t thre)
293 {
294 feedOnceDiffThre_ = thre;
295 }
296
SetTimeStampBaseline(const int64_t timeStmapBaseline)297 void IFeedingSmoother::SetTimeStampBaseline(const int64_t timeStmapBaseline)
298 {
299 timeStampBaseline_ = timeStmapBaseline;
300 }
301
SetClockBaseline(const int64_t clockBaseline)302 void IFeedingSmoother::SetClockBaseline(const int64_t clockBaseline)
303 {
304 clockBaseline_ = clockBaseline;
305 }
306
GetBufferTime()307 int64_t IFeedingSmoother::GetBufferTime()
308 {
309 return bufferTime_;
310 }
311
GetClockTime()312 int64_t IFeedingSmoother::GetClockTime()
313 {
314 return clockTime_;
315 }
316
SetClockTime(const int64_t clockTime)317 void IFeedingSmoother::SetClockTime(const int64_t clockTime)
318 {
319 clockTime_ = clockTime;
320 }
321
SetAdjustSleepFactor(const float factor)322 void IFeedingSmoother::SetAdjustSleepFactor(const float factor)
323 {
324 adjustSleepFactor_ = factor;
325 }
326
SetWaitClockFactor(const float factor)327 void IFeedingSmoother::SetWaitClockFactor(const float factor)
328 {
329 waitClockFactor_ = factor;
330 }
331
SetTrackClockFactor(const float factor)332 void IFeedingSmoother::SetTrackClockFactor(const float factor)
333 {
334 trackClockFactor_ = factor;
335 }
336 } // namespace DistributedHardware
337 } // namespace OHOS