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

Side by Side 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, 6 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/logging.h"
6 #include "mojo/services/media/common/cpp/timeline.h"
7 #include "services/media/factory_service/media_timeline_controller_impl.h"
8 #include "services/media/framework_mojo/mojo_type_conversions.h"
9
10 namespace mojo {
11 namespace media {
12
13 // static
14 std::shared_ptr<MediaTimelineControllerImpl>
15 MediaTimelineControllerImpl::Create(
16 InterfaceRequest<MediaTimelineController> request,
17 MediaFactoryService* owner) {
18 return std::shared_ptr<MediaTimelineControllerImpl>(
19 new MediaTimelineControllerImpl(request.Pass(), owner));
20 }
21
22 MediaTimelineControllerImpl::MediaTimelineControllerImpl(
23 InterfaceRequest<MediaTimelineController> request,
24 MediaFactoryService* owner)
25 : MediaFactoryService::Product<MediaTimelineController>(this,
26 request.Pass(),
27 owner),
28 control_site_binding_(this),
29 consumer_binding_(this) {
30 status_publisher_.SetCallbackRunner(
31 [this](const GetStatusCallback& callback, uint64_t version) {
32 MediaTimelineControlSiteStatusPtr status =
33 MediaTimelineControlSiteStatus::New();
34 status->timeline_transform =
35 mojo::TimelineTransform::From(current_timeline_function_);
36 status->end_of_stream = end_of_stream_;
37 callback.Run(version, status.Pass());
38 });
39 }
40
41 MediaTimelineControllerImpl::~MediaTimelineControllerImpl() {
42 status_publisher_.SendUpdates();
43 }
44
45 void MediaTimelineControllerImpl::AddControlSite(
46 InterfaceHandle<MediaTimelineControlSite> control_site) {
47 site_states_.emplace_back(
48 this, MediaTimelineControlSitePtr::Create(std::move(control_site)));
49 site_states_.back().HandleStatusUpdates();
50 }
51
52 void MediaTimelineControllerImpl::GetControlSite(
53 InterfaceRequest<MediaTimelineControlSite> control_site) {
54 if (control_site_binding_.is_bound()) {
55 control_site_binding_.Close();
56 }
57
58 control_site_binding_.Bind(control_site.Pass());
59 }
60
61 void MediaTimelineControllerImpl::GetStatus(uint64_t version_last_seen,
62 const GetStatusCallback& callback) {
63 status_publisher_.Get(version_last_seen, callback);
64 }
65
66 void MediaTimelineControllerImpl::GetTimelineConsumer(
67 InterfaceRequest<TimelineConsumer> timeline_consumer) {
68 if (consumer_binding_.is_bound()) {
69 consumer_binding_.Close();
70 }
71
72 consumer_binding_.Bind(timeline_consumer.Pass());
73 }
74
75 void MediaTimelineControllerImpl::SetTimelineTransform(
76 int64_t subject_time,
77 uint32_t reference_delta,
78 uint32_t subject_delta,
79 int64_t effective_reference_time,
80 int64_t effective_subject_time,
81 const SetTimelineTransformCallback& callback) {
82 // At most one effective time may be specified.
83 RCHECK(effective_subject_time == kUnspecifiedTime ||
84 effective_reference_time == kUnspecifiedTime);
85 // effective_subject_time can only be specified if we're progressing.
86 RCHECK(effective_subject_time == kUnspecifiedTime ||
87 current_timeline_function_.subject_delta() != 0u);
88 RCHECK(reference_delta != 0);
89
90 // There can only be once SetTimelineTransform transition pending at any
91 // moment, so a new SetTimelineTransform call that arrives before a previous
92 // one completes cancels the previous one. This causes some problems for us,
93 // because some sites may complete the previous transition while other may
94 // not.
95 //
96 // We start by noticing that there's an incomplete previous transition, and
97 // we 'cancel' it, meaning we call its callback with a false complete
98 // parameter.
99 //
100 // If we're cancelling a previous transition, we need to take steps to make
101 // sure the sites will end up in the right state regardless of whether they
102 // completed the previous transition. We do two things:
103 //
104 // 1) If subject_time isn't specified, we infer it here and supply the
105 // inferred value to the sites, so there's no disagreement about its
106 // value.
107 // 2) If the effective_subject_time is specified rather than the
108 // effective_reference_time, we infer effective_reference_time and send
109 // it to the sites instead of effective_subject_time, so there's no
110 // disagreement about effective time and so that no sites reject the
111 // transition due to having a zero subject_delta.
112
113 std::shared_ptr<TimelineTransition> pending_transition =
114 pending_transition_.lock();
115 if (pending_transition) {
116 // A transition is pending - cancel it.
117 pending_transition->Cancel();
118 }
119
120 // These will be recorded as part of the new TimelineFunction.
121 int64_t new_reference_time;
122 int64_t new_subject_time;
123
124 if (effective_subject_time != kUnspecifiedTime) {
125 // Infer new_reference_time from effective_subject_time.
126 new_reference_time =
127 current_timeline_function_.ApplyInverse(effective_subject_time);
128
129 // Figure out what the subject_time will be after this transition.
130 if (subject_time == kUnspecifiedTime) {
131 new_subject_time = effective_subject_time;
132 } else {
133 new_subject_time = subject_time;
134 }
135 } else {
136 if (effective_reference_time == kUnspecifiedTime) {
137 // Neither effective time was specified. Effective time is now.
138 effective_reference_time = Timeline::local_now() + kDefaultLeadTime;
139 }
140
141 // new_reference_time is just effective_reference_time.
142 new_reference_time = effective_reference_time;
143
144 // Figure out what the subject_time will be after this transition.
145 if (subject_time == kUnspecifiedTime) {
146 new_subject_time = current_timeline_function_(effective_reference_time);
147 } else {
148 new_subject_time = subject_time;
149 }
150 }
151
152 if (pending_transition) {
153 // This transition cancels a previous one. Use effective_reference_time
154 // rather than effective_subject_time, because we can't be sure what
155 // effective_subject_time will mean to the sites.
156 effective_reference_time = new_reference_time;
157 effective_subject_time = kUnspecifiedTime;
158
159 // We don't want the sites to have to infer the subject_time, because we
160 // can't be sure what subject_time a site will infer.
161 subject_time = new_subject_time;
162 }
163
164 // Recording the new pending transition.
165 std::shared_ptr<TimelineTransition> transition =
166 std::shared_ptr<TimelineTransition>(
167 new TimelineTransition(new_reference_time, new_subject_time,
168 reference_delta, subject_delta, callback));
169
170 pending_transition_ = transition;
171
172 // Initiate the transition for each site.
173 for (const SiteState& site_state : site_states_) {
174 site_state.consumer_->SetTimelineTransform(
175 subject_time, reference_delta, subject_delta, effective_reference_time,
176 effective_subject_time, transition->NewCallback());
177 }
178
179 // If and when this transition is complete, adopt the new TimelineFunction
180 // and tell any status subscribers.
181 transition->WhenCompleted([this, transition]() {
182 current_timeline_function_ = transition->new_timeline_function();
183 status_publisher_.SendUpdates();
184 });
185 }
186
187 void MediaTimelineControllerImpl::HandleSiteEndOfStreamChange() {
188 bool end_of_stream = true;
189 for (const SiteState& site_state : site_states_) {
190 if (!site_state.end_of_stream_) {
191 end_of_stream = false;
192 break;
193 }
194 }
195
196 if (end_of_stream_ != end_of_stream) {
197 end_of_stream_ = end_of_stream;
198 status_publisher_.SendUpdates();
199 }
200 }
201
202 MediaTimelineControllerImpl::SiteState::SiteState(
203 MediaTimelineControllerImpl* parent,
204 MediaTimelineControlSitePtr site)
205 : parent_(parent), site_(site.Pass()) {
206 site_->GetTimelineConsumer(GetProxy(&consumer_));
207 }
208
209 MediaTimelineControllerImpl::SiteState::SiteState(SiteState&& other)
210 : parent_(other.parent_),
211 site_(other.site_.Pass()),
212 consumer_(other.consumer_.Pass()) {}
213
214 MediaTimelineControllerImpl::SiteState::~SiteState() {}
215
216 void MediaTimelineControllerImpl::SiteState::HandleStatusUpdates(
217 uint64_t version,
218 MediaTimelineControlSiteStatusPtr status) {
219 if (status) {
220 // Respond to any end-of-stream changes.
221 if (end_of_stream_ != status->end_of_stream) {
222 end_of_stream_ = status->end_of_stream;
223 parent_->HandleSiteEndOfStreamChange();
224 }
225 }
226
227 site_->GetStatus(version, [this](uint64_t version,
228 MediaTimelineControlSiteStatusPtr status) {
229 HandleStatusUpdates(version, status.Pass());
230 });
231 }
232
233 MediaTimelineControllerImpl::TimelineTransition::TimelineTransition(
234 int64_t reference_time,
235 int64_t subject_time,
236 uint32_t reference_delta,
237 uint32_t subject_delta,
238 const SetTimelineTransformCallback& callback)
239 : new_timeline_function_(reference_time,
240 subject_time,
241 reference_delta,
242 subject_delta),
243 callback_(callback) {
244 DCHECK(!callback_.is_null());
245 callback_joiner_.WhenJoined([this]() {
246 if (cancelled_) {
247 DCHECK(callback_.is_null());
248 return;
249 }
250
251 DCHECK(!callback_.is_null());
252 callback_.Run(true);
253 callback_.reset();
254 if (!completed_callback_.is_null()) {
255 completed_callback_.Run();
256 completed_callback_.reset();
257 }
258 });
259 }
260
261 MediaTimelineControllerImpl::TimelineTransition::~TimelineTransition() {}
262
263 } // namespace media
264 } // namespace mojo
OLDNEW
« 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