• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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