| Index: services/media/common/timeline_control_site.cc
|
| diff --git a/services/media/common/timeline_control_site.cc b/services/media/common/timeline_control_site.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..26dc07f214a603745aca3408e5bdd86c77683d93
|
| --- /dev/null
|
| +++ b/services/media/common/timeline_control_site.cc
|
| @@ -0,0 +1,193 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/logging.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "mojo/services/media/common/cpp/timeline.h"
|
| +#include "services/media/common/timeline_control_site.h"
|
| +
|
| +namespace mojo {
|
| +namespace media {
|
| +
|
| +// For checking preconditions when handling mojo requests.
|
| +// Checks the condition, and, if it's false, resets and calls return.
|
| +#define RCHECK(condition) \
|
| + if (!(condition)) { \
|
| + LOG(ERROR) << "request precondition failed: " #condition "."; \
|
| + ResetUnsafe(); \
|
| + return; \
|
| + }
|
| +
|
| +TimelineControlSite::TimelineControlSite()
|
| + : control_site_binding_(this), consumer_binding_(this) {
|
| + task_runner_ = base::MessageLoop::current()->task_runner();
|
| + DCHECK(task_runner_);
|
| +
|
| + base::AutoLock lock(lock_);
|
| + ClearPendingTimelineFunctionUnsafe(false);
|
| +
|
| + status_publisher_.SetCallbackRunner(
|
| + [this](const GetStatusCallback& callback, uint64_t version) {
|
| + MediaTimelineControlSiteStatusPtr status;
|
| + {
|
| + base::AutoLock lock(lock_);
|
| + status = MediaTimelineControlSiteStatus::New();
|
| + status->timeline_transform =
|
| + TimelineTransform::From(current_timeline_function_);
|
| + status->end_of_stream = false; // TODO(dalesat): Provide this.
|
| + }
|
| + callback.Run(version, status.Pass());
|
| + });
|
| +}
|
| +
|
| +TimelineControlSite::~TimelineControlSite() {}
|
| +
|
| +void TimelineControlSite::Bind(
|
| + InterfaceRequest<MediaTimelineControlSite> request) {
|
| + if (control_site_binding_.is_bound()) {
|
| + control_site_binding_.Close();
|
| + }
|
| +
|
| + control_site_binding_.Bind(request.Pass());
|
| +}
|
| +
|
| +void TimelineControlSite::Reset() {
|
| + if (control_site_binding_.is_bound()) {
|
| + control_site_binding_.Close();
|
| + }
|
| +
|
| + if (consumer_binding_.is_bound()) {
|
| + consumer_binding_.Close();
|
| + }
|
| +
|
| + {
|
| + base::AutoLock lock(lock_);
|
| + current_timeline_function_ = TimelineFunction();
|
| + ClearPendingTimelineFunctionUnsafe(false);
|
| + generation_ = 1;
|
| + }
|
| +
|
| + status_publisher_.SendUpdates();
|
| +}
|
| +
|
| +void TimelineControlSite::SnapshotCurrentFunction(int64_t reference_time,
|
| + TimelineFunction* out,
|
| + uint32_t* generation) {
|
| + DCHECK(out);
|
| + base::AutoLock lock(lock_);
|
| + ApplyPendingChangesUnsafe(reference_time);
|
| + *out = current_timeline_function_;
|
| + if (generation) {
|
| + *generation = generation_;
|
| + }
|
| +}
|
| +
|
| +void TimelineControlSite::GetStatus(uint64_t version_last_seen,
|
| + const GetStatusCallback& callback) {
|
| + status_publisher_.Get(version_last_seen, callback);
|
| +}
|
| +
|
| +void TimelineControlSite::GetTimelineConsumer(
|
| + InterfaceRequest<TimelineConsumer> timeline_consumer) {
|
| + if (consumer_binding_.is_bound()) {
|
| + consumer_binding_.Close();
|
| + }
|
| +
|
| + consumer_binding_.Bind(timeline_consumer.Pass());
|
| +}
|
| +
|
| +void TimelineControlSite::SetTimelineTransform(
|
| + int64_t subject_time,
|
| + uint32_t reference_delta,
|
| + uint32_t subject_delta,
|
| + int64_t effective_reference_time,
|
| + int64_t effective_subject_time,
|
| + const SetTimelineTransformCallback& callback) {
|
| + base::AutoLock lock(lock_);
|
| +
|
| + // At most one of the effective times must be specified.
|
| + RCHECK(effective_reference_time == kUnspecifiedTime ||
|
| + effective_subject_time == kUnspecifiedTime);
|
| + // effective_subject_time can only be used if we're progressing already.
|
| + RCHECK(effective_subject_time == kUnspecifiedTime ||
|
| + current_timeline_function_.subject_delta() != 0);
|
| + RCHECK(reference_delta != 0);
|
| +
|
| + if (effective_subject_time != kUnspecifiedTime) {
|
| + // Infer effective_reference_time from effective_subject_time.
|
| + effective_reference_time =
|
| + current_timeline_function_.ApplyInverse(effective_subject_time);
|
| +
|
| + if (subject_time == kUnspecifiedTime) {
|
| + // Infer subject_time from effective_subject_time.
|
| + subject_time = effective_subject_time;
|
| + }
|
| + } else {
|
| + if (effective_reference_time == kUnspecifiedTime) {
|
| + // Neither effective time was specified. Effective time is now.
|
| + effective_reference_time = Timeline::local_now();
|
| + }
|
| +
|
| + if (subject_time == kUnspecifiedTime) {
|
| + // Infer subject_time from effective_reference_time.
|
| + subject_time = current_timeline_function_(effective_reference_time);
|
| + }
|
| + }
|
| +
|
| + // Eject any previous pending change.
|
| + ClearPendingTimelineFunctionUnsafe(false);
|
| +
|
| + // Queue up the new pending change.
|
| + pending_timeline_function_ = TimelineFunction(
|
| + effective_reference_time, subject_time, reference_delta, subject_delta);
|
| +
|
| + set_timeline_transform_callback_ = callback;
|
| +}
|
| +
|
| +void TimelineControlSite::ApplyPendingChangesUnsafe(int64_t reference_time) {
|
| + lock_.AssertAcquired();
|
| +
|
| + if (!TimelineFunctionPendingUnsafe() ||
|
| + pending_timeline_function_.reference_time() > reference_time) {
|
| + return;
|
| + }
|
| +
|
| + current_timeline_function_ = pending_timeline_function_;
|
| + ClearPendingTimelineFunctionUnsafe(true);
|
| +
|
| + ++generation_;
|
| +
|
| + task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(&MojoPublisher<GetStatusCallback>::SendUpdates,
|
| + base::Unretained(&status_publisher_)));
|
| +}
|
| +
|
| +void TimelineControlSite::ClearPendingTimelineFunctionUnsafe(bool completed) {
|
| + lock_.AssertAcquired();
|
| +
|
| + pending_timeline_function_ =
|
| + TimelineFunction(kUnspecifiedTime, kUnspecifiedTime, 1, 0);
|
| + if (!set_timeline_transform_callback_.is_null()) {
|
| + task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(&TimelineControlSite::RunCallback,
|
| + set_timeline_transform_callback_, completed));
|
| + set_timeline_transform_callback_.reset();
|
| + }
|
| +}
|
| +
|
| +void TimelineControlSite::ResetUnsafe() {
|
| + lock_.AssertAcquired();
|
| + task_runner_->PostTask(FROM_HERE, base::Bind(&TimelineControlSite::Reset,
|
| + base::Unretained(this)));
|
| +}
|
| +
|
| +// static
|
| +void TimelineControlSite::RunCallback(SetTimelineTransformCallback callback,
|
| + bool completed) {
|
| + callback.Run(completed);
|
| +}
|
| +
|
| +} // namespace media
|
| +} // namespace mojo
|
|
|