Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(411)

Unified Diff: services/media/factory_service/media_timeline_controller_impl.cc

Issue 2009643002: Motown: Implement MediaTimelineController and use it. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Sync Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: services/media/factory_service/media_timeline_controller_impl.cc
diff --git a/services/media/factory_service/media_timeline_controller_impl.cc b/services/media/factory_service/media_timeline_controller_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..54bb564ee9fb75eee287ab02d60ea4854219122b
--- /dev/null
+++ b/services/media/factory_service/media_timeline_controller_impl.cc
@@ -0,0 +1,264 @@
+// 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/logging.h"
+#include "mojo/services/media/common/cpp/timeline.h"
+#include "services/media/factory_service/media_timeline_controller_impl.h"
+#include "services/media/framework_mojo/mojo_type_conversions.h"
+
+namespace mojo {
+namespace media {
+
+// static
+std::shared_ptr<MediaTimelineControllerImpl>
+MediaTimelineControllerImpl::Create(
+ InterfaceRequest<MediaTimelineController> request,
+ MediaFactoryService* owner) {
+ return std::shared_ptr<MediaTimelineControllerImpl>(
+ new MediaTimelineControllerImpl(request.Pass(), owner));
+}
+
+MediaTimelineControllerImpl::MediaTimelineControllerImpl(
+ InterfaceRequest<MediaTimelineController> request,
+ MediaFactoryService* owner)
+ : MediaFactoryService::Product<MediaTimelineController>(this,
+ request.Pass(),
+ owner),
+ control_site_binding_(this),
+ consumer_binding_(this) {
+ status_publisher_.SetCallbackRunner(
+ [this](const GetStatusCallback& callback, uint64_t version) {
+ MediaTimelineControlSiteStatusPtr status =
+ MediaTimelineControlSiteStatus::New();
+ status->timeline_transform =
+ mojo::TimelineTransform::From(current_timeline_function_);
+ status->end_of_stream = end_of_stream_;
+ callback.Run(version, status.Pass());
+ });
+}
+
+MediaTimelineControllerImpl::~MediaTimelineControllerImpl() {
+ status_publisher_.SendUpdates();
+}
+
+void MediaTimelineControllerImpl::AddControlSite(
+ InterfaceHandle<MediaTimelineControlSite> control_site) {
+ site_states_.emplace_back(
+ this, MediaTimelineControlSitePtr::Create(std::move(control_site)));
+ site_states_.back().HandleStatusUpdates();
+}
+
+void MediaTimelineControllerImpl::GetControlSite(
+ InterfaceRequest<MediaTimelineControlSite> control_site) {
+ if (control_site_binding_.is_bound()) {
+ control_site_binding_.Close();
+ }
+
+ control_site_binding_.Bind(control_site.Pass());
+}
+
+void MediaTimelineControllerImpl::GetStatus(uint64_t version_last_seen,
+ const GetStatusCallback& callback) {
+ status_publisher_.Get(version_last_seen, callback);
+}
+
+void MediaTimelineControllerImpl::GetTimelineConsumer(
+ InterfaceRequest<TimelineConsumer> timeline_consumer) {
+ if (consumer_binding_.is_bound()) {
+ consumer_binding_.Close();
+ }
+
+ consumer_binding_.Bind(timeline_consumer.Pass());
+}
+
+void MediaTimelineControllerImpl::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) {
+ // At most one effective time may be specified.
+ RCHECK(effective_subject_time == kUnspecifiedTime ||
+ effective_reference_time == kUnspecifiedTime);
+ // effective_subject_time can only be specified if we're progressing.
+ RCHECK(effective_subject_time == kUnspecifiedTime ||
+ current_timeline_function_.subject_delta() != 0u);
+ RCHECK(reference_delta != 0);
+
+ // There can only be once SetTimelineTransform transition pending at any
+ // moment, so a new SetTimelineTransform call that arrives before a previous
+ // one completes cancels the previous one. This causes some problems for us,
+ // because some sites may complete the previous transition while other may
+ // not.
+ //
+ // We start by noticing that there's an incomplete previous transition, and
+ // we 'cancel' it, meaning we call its callback with a false complete
+ // parameter.
+ //
+ // If we're cancelling a previous transition, we need to take steps to make
+ // sure the sites will end up in the right state regardless of whether they
+ // completed the previous transition. We do two things:
+ //
+ // 1) If subject_time isn't specified, we infer it here and supply the
+ // inferred value to the sites, so there's no disagreement about its
+ // value.
+ // 2) If the effective_subject_time is specified rather than the
+ // effective_reference_time, we infer effective_reference_time and send
+ // it to the sites instead of effective_subject_time, so there's no
+ // disagreement about effective time and so that no sites reject the
+ // transition due to having a zero subject_delta.
+
+ std::shared_ptr<TimelineTransition> pending_transition =
+ pending_transition_.lock();
+ if (pending_transition) {
+ // A transition is pending - cancel it.
+ pending_transition->Cancel();
+ }
+
+ // These will be recorded as part of the new TimelineFunction.
+ int64_t new_reference_time;
+ int64_t new_subject_time;
+
+ if (effective_subject_time != kUnspecifiedTime) {
+ // Infer new_reference_time from effective_subject_time.
+ new_reference_time =
+ current_timeline_function_.ApplyInverse(effective_subject_time);
+
+ // Figure out what the subject_time will be after this transition.
+ if (subject_time == kUnspecifiedTime) {
+ new_subject_time = effective_subject_time;
+ } else {
+ new_subject_time = subject_time;
+ }
+ } else {
+ if (effective_reference_time == kUnspecifiedTime) {
+ // Neither effective time was specified. Effective time is now.
+ effective_reference_time = Timeline::local_now() + kDefaultLeadTime;
+ }
+
+ // new_reference_time is just effective_reference_time.
+ new_reference_time = effective_reference_time;
+
+ // Figure out what the subject_time will be after this transition.
+ if (subject_time == kUnspecifiedTime) {
+ new_subject_time = current_timeline_function_(effective_reference_time);
+ } else {
+ new_subject_time = subject_time;
+ }
+ }
+
+ if (pending_transition) {
+ // This transition cancels a previous one. Use effective_reference_time
+ // rather than effective_subject_time, because we can't be sure what
+ // effective_subject_time will mean to the sites.
+ effective_reference_time = new_reference_time;
+ effective_subject_time = kUnspecifiedTime;
+
+ // We don't want the sites to have to infer the subject_time, because we
+ // can't be sure what subject_time a site will infer.
+ subject_time = new_subject_time;
+ }
+
+ // Recording the new pending transition.
+ std::shared_ptr<TimelineTransition> transition =
+ std::shared_ptr<TimelineTransition>(
+ new TimelineTransition(new_reference_time, new_subject_time,
+ reference_delta, subject_delta, callback));
+
+ pending_transition_ = transition;
+
+ // Initiate the transition for each site.
+ for (const SiteState& site_state : site_states_) {
+ site_state.consumer_->SetTimelineTransform(
+ subject_time, reference_delta, subject_delta, effective_reference_time,
+ effective_subject_time, transition->NewCallback());
+ }
+
+ // If and when this transition is complete, adopt the new TimelineFunction
+ // and tell any status subscribers.
+ transition->WhenCompleted([this, transition]() {
+ current_timeline_function_ = transition->new_timeline_function();
+ status_publisher_.SendUpdates();
+ });
+}
+
+void MediaTimelineControllerImpl::HandleSiteEndOfStreamChange() {
+ bool end_of_stream = true;
+ for (const SiteState& site_state : site_states_) {
+ if (!site_state.end_of_stream_) {
+ end_of_stream = false;
+ break;
+ }
+ }
+
+ if (end_of_stream_ != end_of_stream) {
+ end_of_stream_ = end_of_stream;
+ status_publisher_.SendUpdates();
+ }
+}
+
+MediaTimelineControllerImpl::SiteState::SiteState(
+ MediaTimelineControllerImpl* parent,
+ MediaTimelineControlSitePtr site)
+ : parent_(parent), site_(site.Pass()) {
+ site_->GetTimelineConsumer(GetProxy(&consumer_));
+}
+
+MediaTimelineControllerImpl::SiteState::SiteState(SiteState&& other)
+ : parent_(other.parent_),
+ site_(other.site_.Pass()),
+ consumer_(other.consumer_.Pass()) {}
+
+MediaTimelineControllerImpl::SiteState::~SiteState() {}
+
+void MediaTimelineControllerImpl::SiteState::HandleStatusUpdates(
+ uint64_t version,
+ MediaTimelineControlSiteStatusPtr status) {
+ if (status) {
+ // Respond to any end-of-stream changes.
+ if (end_of_stream_ != status->end_of_stream) {
+ end_of_stream_ = status->end_of_stream;
+ parent_->HandleSiteEndOfStreamChange();
+ }
+ }
+
+ site_->GetStatus(version, [this](uint64_t version,
+ MediaTimelineControlSiteStatusPtr status) {
+ HandleStatusUpdates(version, status.Pass());
+ });
+}
+
+MediaTimelineControllerImpl::TimelineTransition::TimelineTransition(
+ int64_t reference_time,
+ int64_t subject_time,
+ uint32_t reference_delta,
+ uint32_t subject_delta,
+ const SetTimelineTransformCallback& callback)
+ : new_timeline_function_(reference_time,
+ subject_time,
+ reference_delta,
+ subject_delta),
+ callback_(callback) {
+ DCHECK(!callback_.is_null());
+ callback_joiner_.WhenJoined([this]() {
+ if (cancelled_) {
+ DCHECK(callback_.is_null());
+ return;
+ }
+
+ DCHECK(!callback_.is_null());
+ callback_.Run(true);
+ callback_.reset();
+ if (!completed_callback_.is_null()) {
+ completed_callback_.Run();
+ completed_callback_.reset();
+ }
+ });
+}
+
+MediaTimelineControllerImpl::TimelineTransition::~TimelineTransition() {}
+
+} // namespace media
+} // namespace mojo
« no previous file with comments | « services/media/factory_service/media_timeline_controller_impl.h ('k') | services/media/framework/util/callback_joiner.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698