* Copyright (c) 2026 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 "interstitial_scheduler.h"
#include <cinttypes>
#include "common/log.h"
namespace OHOS {
namespace Media {
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_DEMUXER, "InterstitialScheduler"};
}
InterstitialScheduler::InterstitialScheduler()
{
MEDIA_LOG_I("InterstitialScheduler created");
}
InterstitialScheduler::~InterstitialScheduler()
{
MEDIA_LOG_I("InterstitialScheduler destroyed");
}
void InterstitialScheduler::SetSyncCenter(std::shared_ptr<MediaSyncManager> syncCenter)
{
syncCenter_ = std::move(syncCenter);
MEDIA_LOG_I("SetSyncCenter OK");
}
void InterstitialScheduler::SetNotifyCallback(NotifyCallback callback)
{
notifyCallback_ = std::move(callback);
MEDIA_LOG_I("SetNotifyCallback OK");
}
void InterstitialScheduler::SetScheduleStrategy(std::shared_ptr<IScheduleStrategy> strategy)
{
scheduleStrategy_ = std::move(strategy);
MEDIA_LOG_I("SetScheduleStrategy OK");
}
std::shared_ptr<IScheduleStrategy> InterstitialScheduler::GetScheduleStrategy() const
{
return scheduleStrategy_;
}
void InterstitialScheduler::CollectEvent(const std::shared_ptr<MediaAVCodec::AVTimedMetaData>& metadata)
{
FALSE_RETURN_MSG(metadata != nullptr, "CollectEvent: metadata is null");
bool immediateNotify = false;
{
std::lock_guard<std::mutex> lock(mutex_);
for (const auto& entry : pendingEvents_) {
if (entry.metadata != nullptr && entry.metadata->id == metadata->id) {
MEDIA_LOG_D("CollectEvent: duplicate event id=%{public}s, skip", metadata->id.c_str());
return;
}
}
pendingEvents_.push_back(TimedEventEntry{metadata, false});
if (metadata->start <= NOTIFY_ADVANCE_MS) {
pendingEvents_.back().notified = true;
immediateNotify = true;
}
}
if (immediateNotify && notifyCallback_) {
notifyCallback_(metadata);
}
MEDIA_LOG_I("collected event id=%{public}s, startMs=" PUBLIC_LOG_D64, metadata->id.c_str(), metadata->start);
}
void InterstitialScheduler::OnPlaybackTick()
{
FALSE_RETURN_MSG(syncCenter_ != nullptr, "OnPlaybackTick: syncCenter is null");
int64_t currentPosMs = syncCenter_->GetMediaTimeNow() / US_PER_MS;
if (currentPosMs <= 0) {
return;
}
CheckAndNotify(currentPosMs);
if (scheduleStrategy_) {
std::lock_guard<std::mutex> lock(mutex_);
scheduleStrategy_->TrimExpiredEvents(pendingEvents_, currentPosMs);
}
}
void InterstitialScheduler::OnSeek(int64_t seekTargetMs)
{
if (scheduleStrategy_) {
std::lock_guard<std::mutex> lock(mutex_);
scheduleStrategy_->OnSeek(pendingEvents_, seekTargetMs);
}
MEDIA_LOG_I("OnSeek: seekTargetMs=%" PRId64, seekTargetMs);
}
void InterstitialScheduler::OnStop()
{
std::lock_guard<std::mutex> lock(mutex_);
pendingEvents_.clear();
MEDIA_LOG_I("OnStop: cleared all events");
}
void InterstitialScheduler::CheckAndNotify(int64_t currentPosMs)
{
std::vector<std::shared_ptr<MediaAVCodec::AVTimedMetaData>> toNotify;
{
std::lock_guard<std::mutex> lock(mutex_);
for (auto& entry : pendingEvents_) {
if (entry.metadata == nullptr || entry.notified) {
continue;
}
if (currentPosMs >= (entry.metadata->start - NOTIFY_ADVANCE_MS)) {
entry.notified = true;
toNotify.push_back(entry.metadata);
MEDIA_LOG_I("CheckAndNotify: marking notify for id=%{public}s, startMs=%" PRId64,
entry.metadata->id.c_str(), entry.metadata->start);
}
}
}
for (const auto& meta : toNotify) {
if (notifyCallback_) {
notifyCallback_(meta);
}
}
}
}
}