blob: e9ef09ca2bf3cf008d3a1e0189be912223247ea1 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <memory>
#include <vector>
#include "garnet/bin/media/media_service/media_service_impl.h"
#include "garnet/bin/media/util/callback_joiner.h"
#include "garnet/bin/media/util/fidl_publisher.h"
#include "lib/fidl/cpp/bindings/binding.h"
#include "lib/media/fidl/timeline_controller.fidl.h"
#include "lib/media/timeline/timeline.h"
#include "lib/media/timeline/timeline_function.h"
namespace media {
// Fidl agent that controls timing in a graph.
class MediaTimelineControllerImpl
: public MediaServiceImpl::Product<MediaTimelineController>,
public MediaTimelineController,
public MediaTimelineControlPoint,
public TimelineConsumer {
public:
static std::shared_ptr<MediaTimelineControllerImpl> Create(
fidl::InterfaceRequest<MediaTimelineController> request,
MediaServiceImpl* owner);
~MediaTimelineControllerImpl() override;
// MediaTimelineController implementation.
void AddControlPoint(
fidl::InterfaceHandle<MediaTimelineControlPoint> control_point) override;
void GetControlPoint(
fidl::InterfaceRequest<MediaTimelineControlPoint> control_point) override;
// MediaTimelineControlPoint implementation.
void GetStatus(uint64_t version_last_seen,
const GetStatusCallback& callback) override;
void GetTimelineConsumer(
fidl::InterfaceRequest<TimelineConsumer> timeline_consumer) override;
void SetProgramRange(uint64_t program,
int64_t min_pts,
int64_t max_pts) override;
void Prime(const PrimeCallback& callback) override;
// TimelineConsumer implementation.
void SetTimelineTransform(
TimelineTransformPtr timeline_transform,
const SetTimelineTransformCallback& callback) override;
void SetTimelineTransformNoReply(
TimelineTransformPtr timeline_transform) override;
private:
static constexpr int64_t kDefaultLeadTime = Timeline::ns_from_ms(30);
// Relationship to subordinate control point.
struct ControlPointState {
ControlPointState(MediaTimelineControllerImpl* parent,
MediaTimelineControlPointPtr control_point);
~ControlPointState();
void HandleStatusUpdates(
uint64_t version = MediaTimelineControlPoint::kInitialStatus,
MediaTimelineControlPointStatusPtr status = nullptr);
MediaTimelineControllerImpl* parent_;
MediaTimelineControlPointPtr control_point_;
TimelineConsumerPtr consumer_;
bool end_of_stream_ = false;
};
class TimelineTransition
: public std::enable_shared_from_this<TimelineTransition> {
public:
TimelineTransition(int64_t reference_time,
int64_t subject_time,
uint32_t reference_delta,
uint32_t subject_delta,
const SetTimelineTransformCallback& callback);
~TimelineTransition();
// Returns a new callback for a child (control point) transition. THIS
// METHOD WILL ONLY WORK IF THERE IS ALREADY A SHARED POINTER TO THIS
// OBJECT.
std::function<void(bool)> NewCallback() {
callback_joiner_.Spawn();
std::shared_ptr<TimelineTransition> this_ptr = shared_from_this();
FXL_DCHECK(!this_ptr.unique());
return
[this_ptr](bool completed) {
FXL_DCHECK(this_ptr);
if (!completed && !this_ptr->cancelled_) {
FXL_LOG(WARNING)
<< "A control point transition was cancelled unexpectedly.";
}
this_ptr->callback_joiner_.Complete();
};
}
// Cancels this transition.
void Cancel() {
FXL_DCHECK(!cancelled_);
cancelled_ = true;
if (callback_) {
callback_(false);
callback_ = nullptr;
}
completed_callback_ = nullptr;
}
// Specifies a callback to be called if and when the transition is complete.
// The callback will never be called if the transition is cancelled.
void WhenCompleted(const std::function<void()>& completed_callback) {
FXL_DCHECK(!completed_callback_);
if (!callback_ && !cancelled_) {
completed_callback();
} else {
completed_callback_ = completed_callback;
}
}
// Returns the TimelineFunction that will result from this transition.
const TimelineFunction& new_timeline_function() const {
return new_timeline_function_;
}
private:
TimelineFunction new_timeline_function_;
SetTimelineTransformCallback callback_;
CallbackJoiner callback_joiner_;
bool cancelled_ = false;
std::function<void()> completed_callback_;
};
MediaTimelineControllerImpl(
fidl::InterfaceRequest<MediaTimelineController> request,
MediaServiceImpl* owner);
// Takes action when a control point changes its end-of-stream value.
void HandleControlPointEndOfStreamChange();
fidl::Binding<MediaTimelineControlPoint> control_point_binding_;
fidl::Binding<TimelineConsumer> consumer_binding_;
FidlPublisher<GetStatusCallback> status_publisher_;
std::vector<std::unique_ptr<ControlPointState>> control_point_states_;
TimelineFunction current_timeline_function_;
bool end_of_stream_ = false;
std::weak_ptr<TimelineTransition> pending_transition_;
};
} // namespace media