* Copyright (c) 2023-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "time_broker.h"
#include "steady_clock.h"
#include "camera_log.h"
namespace OHOS {
namespace CameraStandard {
namespace DeferredProcessing {
std::shared_ptr<TimeBroker> TimeBroker::Create(std::string name)
{
MEDIA_DEBUG_LOG("(%s) created.", name.c_str());
auto timeBroker = std::make_shared<TimeBroker>(std::move(name));
timeBroker->Initialize();
return timeBroker;
}
TimeBroker::TimeBroker(std::string name)
: name_(std::move(name)), timer_(nullptr), timerInfos_(), expiringTimers_()
{
MEDIA_DEBUG_LOG("(%s) entered.", name_.c_str());
}
TimeBroker::~TimeBroker()
{
std::lock_guard<std::mutex> lock(mutex_);
MEDIA_DEBUG_LOG("(%s) entered.", name_.c_str());
if (timer_) {
timer_->Stop();
timer_.reset();
}
timerInfos_.clear();
expiringTimers_.clear();
}
void TimeBroker::Initialize()
{
std::weak_ptr<TimeBroker> weakThis(shared_from_this());
timer_ = Timer::Create(name_, TimerType::ONCE, 0, [weakThis]() {
if (auto timeBroker = weakThis.lock()) {
timeBroker->TimerExpired();
}
});
}
bool TimeBroker::RegisterCallback(uint32_t delayTimeMs, std::function<void(uint32_t handle)> timerCallback,
uint32_t& handle)
{
std::lock_guard<std::mutex> lock(mutex_);
MEDIA_DEBUG_LOG("(%s) register callback with delayTimeMs (%{public}d).",
name_.c_str(), static_cast<int>(delayTimeMs));
auto ret = GetNextHandle(handle);
if (ret) {
auto timestamp = SteadyClock::GetTimestampMilli() + delayTimeMs;
auto timerInfo = std::make_shared<TimerInfo>(handle, timestamp, std::move(timerCallback));
expiringTimers_[timestamp].push_back(timerInfo);
timerInfos_.emplace(handle, timerInfo);
timeline_.push(timestamp);
if (timestamp == timeline_.top()) {
timer_->StartAt(timestamp);
}
}
return ret;
}
void TimeBroker::DeregisterCallback(uint32_t handle)
{
std::lock_guard<std::mutex> lock(mutex_);
if (handle == 0) {
MEDIA_DEBUG_LOG("(%s) invalid handle (%{public}d).", name_.c_str(), static_cast<int>(handle));
return;
}
timerInfos_.erase(handle);
}
std::function<void(uint32_t handle)> TimeBroker::GetExpiredFunc(uint32_t handle)
{
std::lock_guard<std::mutex> lock(mutex_);
if (timerInfos_.count(handle)) {
return timerInfos_[handle]->timerCallback;
}
return [](uint32_t handle) {
MEDIA_ERR_LOG("GetExpiredFunc invalid ExpiredFunc (%{public}d).", static_cast<int>(handle));
};
}
bool TimeBroker::GetNextHandle(uint32_t& handle)
{
do {
handle = GenerateHandle();
} while (timerInfos_.count(handle) != 0 && handle != preHandle_);
if (handle != preHandle_) {
preHandle_ = handle;
return true;
}
return false;
}
uint32_t TimeBroker::GenerateHandle()
{
static uint32_t handle = 0;
if (++handle == 0) {
++handle;
}
return handle;
}
void TimeBroker::TimerExpired()
{
std::vector<std::shared_ptr<TimerInfo>> timerInfos;
{
std::lock_guard<std::mutex> lock(mutex_);
MEDIA_DEBUG_LOG("(%s) TimerExpired.", name_.c_str());
if (timeline_.empty()) {
MEDIA_DEBUG_LOG("(%s) unexpected TimerExpired", name_.c_str());
return;
}
auto timestamp = timeline_.top();
timeline_.pop();
timerInfos.reserve(expiringTimers_[timestamp].size());
for (auto& weakTimerInfoPtr : expiringTimers_[timestamp]) {
if (auto timerInfo = weakTimerInfoPtr.lock()) {
timerInfos_.erase(timerInfo->handle);
timerInfos.push_back(std::move(timerInfo));
}
}
expiringTimers_.erase(timestamp);
auto ret = RestartTimer(timestamp);
if (!ret) {
MEDIA_DEBUG_LOG("(%s) RestartTimer failed (%{public}d)", name_.c_str(), ret);
}
}
for (auto &timerInfo : timerInfos) {
timerInfo->timerCallback(timerInfo->handle);
}
}
bool TimeBroker::RestartTimer(bool force)
{
if (timeline_.empty() || (timer_->IsActive() && force == false)) {
MEDIA_DEBUG_LOG("(%s) RestartTimer unnecessary.", name_.c_str());
return true;
}
auto timestamp = timeline_.top();
MEDIA_DEBUG_LOG("(%s) restart timer, expiring timestamp: %{public}d", name_.c_str(), static_cast<int>(timestamp));
return timer_->StartAt(timestamp);
}
}
}
}