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 int64_t enterTime = GetNowTimeStampUs();
99 SetClockTime(enterTime);
100 int64_t timeStamp = data->GetTimeStamp();
101 if (timeStamp == 0) {
102 return;
103 }
104 if (!CheckIsProcessInDynamicBalance() || !CheckIsTimeInit()) {
105 RecordTime(enterTime, timeStamp);
106 return;
107 }
108
109 if (!CheckIsBaselineInit()) {
110 InitBaseline(timeStamp, clockTime_);
111 }
112 int64_t interval = timeStamp - lastTimeStamp_;
113 int64_t elapse = enterTime - leaveTime_;
114 int64_t render = enterTime - lastEnterTime_;
115 int64_t delta = render - sleep_ - elapse;
116 delta_ += delta;
117 int64_t clock = timeStampBaseline_ + clockTime_ - clockBaseline_;
118 sleep_ = interval - elapse;
119 AdjustSleepTime(interval);
120 SyncClock(timeStamp, interval, clock);
121 {
122 std::unique_lock<std::mutex> lock(sleepMutex_);
123 sleepCon_.wait_for(lock, std::chrono::microseconds(sleep_), [this] {
124 return (this->state_ == SMOOTH_STOP);
125 });
126 if (state_ == SMOOTH_STOP) {
127 DHLOGD("Notify to interrupt sleep.");
128 return;
129 }
130 }
131 RecordTime(enterTime, timeStamp);
132 }
133
CheckIsProcessInDynamicBalance()134 bool IFeedingSmoother::CheckIsProcessInDynamicBalance()
135 {
136 if (isInDynamicBalance_.load()) {
137 return true;
138 }
139 if (CheckIsProcessInDynamicBalanceOnce()) {
140 dynamicBalanceCount_++;
141 } else {
142 dynamicBalanceCount_ = 0;
143 }
144 if (dynamicBalanceCount_ >= dynamicBalanceThre_) {
145 isInDynamicBalance_.store(true);
146 return true;
147 }
148 return false;
149 }
150
CheckIsProcessInDynamicBalanceOnce()151 bool IFeedingSmoother::CheckIsProcessInDynamicBalanceOnce()
152 {
153 if (statistician_ == nullptr) {
154 return false;
155 }
156 int64_t feedInterval = statistician_->GetFeedInterval();
157 int64_t averFeedInterval = statistician_->GetAverFeedInterval();
158 int64_t averTimeStamapInterval = statistician_->GetAverTimeStampInterval();
159 int64_t averIntervalDiff = averFeedInterval - averTimeStamapInterval;
160 int64_t feedOnceDiff = feedInterval - averFeedInterval;
161 return (averFeedInterval != 0) && (averTimeStamapInterval != 0) &&
162 (llabs(averIntervalDiff) < averIntervalDiffThre_) && (llabs(feedOnceDiff) < feedOnceDiffThre_);
163 }
164
CheckIsBaselineInit()165 bool IFeedingSmoother::CheckIsBaselineInit()
166 {
167 return isBaselineInit_.load();
168 }
169
CheckIsTimeInit()170 bool IFeedingSmoother::CheckIsTimeInit()
171 {
172 return isTimeInit_.load();
173 }
174
InitBaseline(const int64_t timeStampBaseline,const int64_t clockBaseline)175 void IFeedingSmoother::InitBaseline(const int64_t timeStampBaseline, const int64_t clockBaseline)
176 {
177 SetTimeStampBaseline(timeStampBaseline);
178 SetClockBaseline(clockBaseline + bufferTime_);
179 isBaselineInit_.store(true);
180 }
181
NotifySmoothFinished(const std::shared_ptr<IFeedableData> & data)182 int32_t IFeedingSmoother::NotifySmoothFinished(const std::shared_ptr<IFeedableData>& data)
183 {
184 if (listener_ == nullptr) {
185 DHLOGE("Smoother listener is nullptr.");
186 return NOTIFY_FAILED;
187 }
188 return listener_->OnSmoothFinished(data);
189 }
190
AdjustSleepTime(const int64_t interval)191 void IFeedingSmoother::AdjustSleepTime(const int64_t interval)
192 {
193 const int64_t adjustThre = interval * adjustSleepFactor_;
194 if (delta_ > adjustThre && sleep_ > 0) {
195 int64_t sleep = sleep_ - adjustThre;
196 delta_ -= (sleep < 0) ? sleep_ : adjustThre;
197 sleep_ = sleep;
198 DHLOGD("Delta more than thre, adjust sleep to %{public}" PRId64" us.", sleep_);
199 } else if (delta_ < -adjustThre) {
200 sleep_ += delta_;
201 delta_ = 0;
202 DHLOGD("Delta less than negative thre, adjust sleep to %{public}" PRId64" us.", sleep_);
203 }
204 }
205
SyncClock(const int64_t timeStamp,const int64_t interval,const int64_t clock)206 void IFeedingSmoother::SyncClock(const int64_t timeStamp, const int64_t interval, const int64_t clock)
207 {
208 const int64_t waitThre = interval * waitClockFactor_;
209 const int64_t trackThre = interval * trackClockFactor_;
210 int64_t offset = timeStamp - sleep_ - clock;
211 if (offset > waitThre || offset < -trackThre) {
212 sleep_ += offset;
213 DHLOGD("Offset is not in the threshold range, adjust sleep to %{public}" PRId64" us.", sleep_);
214 }
215 if (sleep_ < 0) {
216 sleep_ = 0;
217 DHLOGD("Sleep less than zero, adjust sleep to zero.");
218 }
219 DHLOGD("Offset is %{public}" PRId64" us, sleep is %{public}" PRId64" us after syncing clock.", offset, sleep_);
220 }
221
RecordTime(const int64_t enterTime,const int64_t timeStamp)222 void IFeedingSmoother::RecordTime(const int64_t enterTime, const int64_t timeStamp)
223 {
224 lastEnterTime_ = enterTime;
225 lastTimeStamp_ = timeStamp;
226 leaveTime_ = GetNowTimeStampUs();
227 isTimeInit_.store(true);
228 }
229
StopSmooth()230 int32_t IFeedingSmoother::StopSmooth()
231 {
232 {
233 std::lock_guard<std::mutex> lock(stateMutex_);
234 if (state_ == SMOOTH_STOP) {
235 DHLOGD("Smooth is stoped.");
236 return SMOOTH_IS_STOPED;
237 }
238 state_ = SMOOTH_STOP;
239 }
240 statistician_ = nullptr;
241 UnregisterListener();
242 smoothCon_.notify_one();
243 sleepCon_.notify_one();
244 smoothThread_.join();
245 std::queue<std::shared_ptr<IFeedableData>>().swap(dataQueue_);
246 DHLOGD("Stop smooth success.");
247 return SMOOTH_SUCCESS;
248 }
249
InitTimeStatistician()250 void IFeedingSmoother::InitTimeStatistician()
251 {
252 if (statistician_ != nullptr) {
253 return;
254 }
255 statistician_ = std::make_shared<TimeStatistician>();
256 }
257
RegisterListener(const std::shared_ptr<FeedingSmootherListener> & listener)258 void IFeedingSmoother::RegisterListener(const std::shared_ptr<FeedingSmootherListener>& listener)
259 {
260 listener_ = listener;
261 }
262
UnregisterListener()263 void IFeedingSmoother::UnregisterListener()
264 {
265 listener_ = nullptr;
266 }
267
SetBufferTime(const int32_t time)268 void IFeedingSmoother::SetBufferTime(const int32_t time)
269 {
270 bufferTime_ = time;
271 }
272
SetDynamicBalanceThre(const uint8_t thre)273 void IFeedingSmoother::SetDynamicBalanceThre(const uint8_t thre)
274 {
275 dynamicBalanceThre_ = thre;
276 }
277
SetProcessDynamicBalanceState(const bool state)278 void IFeedingSmoother::SetProcessDynamicBalanceState(const bool state)
279 {
280 isInDynamicBalance_.store(state);
281 }
282
SetAverIntervalDiffThre(const uint32_t thre)283 void IFeedingSmoother::SetAverIntervalDiffThre(const uint32_t thre)
284 {
285 averIntervalDiffThre_ = thre;
286 }
287
SetFeedOnceDiffThre(const uint32_t thre)288 void IFeedingSmoother::SetFeedOnceDiffThre(const uint32_t thre)
289 {
290 feedOnceDiffThre_ = thre;
291 }
292
SetTimeStampBaseline(const int64_t timeStmapBaseline)293 void IFeedingSmoother::SetTimeStampBaseline(const int64_t timeStmapBaseline)
294 {
295 timeStampBaseline_ = timeStmapBaseline;
296 }
297
SetClockBaseline(const int64_t clockBaseline)298 void IFeedingSmoother::SetClockBaseline(const int64_t clockBaseline)
299 {
300 clockBaseline_ = clockBaseline;
301 }
302
GetBufferTime()303 int64_t IFeedingSmoother::GetBufferTime()
304 {
305 return bufferTime_;
306 }
307
GetClockTime()308 int64_t IFeedingSmoother::GetClockTime()
309 {
310 return clockTime_;
311 }
312
SetClockTime(const int64_t clockTime)313 void IFeedingSmoother::SetClockTime(const int64_t clockTime)
314 {
315 clockTime_ = clockTime;
316 }
317
SetAdjustSleepFactor(const float factor)318 void IFeedingSmoother::SetAdjustSleepFactor(const float factor)
319 {
320 adjustSleepFactor_ = factor;
321 }
322
SetWaitClockFactor(const float factor)323 void IFeedingSmoother::SetWaitClockFactor(const float factor)
324 {
325 waitClockFactor_ = factor;
326 }
327
SetTrackClockFactor(const float factor)328 void IFeedingSmoother::SetTrackClockFactor(const float factor)
329 {
330 trackClockFactor_ = factor;
331 }
332 } // namespace DistributedHardware
333 } // namespace OHOS