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

Side by Side Diff: media/mojo/services/mojo_renderer_service.cc

Issue 680533004: Modify MojoRendererService to host a RendererImpl. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments. Created 6 years, 1 month 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
« no previous file with comments | « media/mojo/services/mojo_renderer_service.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/mojo/services/mojo_renderer_service.h" 5 #include "media/mojo/services/mojo_renderer_service.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/memory/scoped_vector.h" 9 #include "base/memory/scoped_vector.h"
10 #include "media/base/audio_decoder.h" 10 #include "media/base/audio_decoder.h"
11 #include "media/base/audio_renderer.h" 11 #include "media/base/audio_renderer.h"
12 #include "media/base/audio_renderer_sink.h" 12 #include "media/base/audio_renderer_sink.h"
13 #include "media/base/decryptor.h" 13 #include "media/base/decryptor.h"
14 #include "media/base/media_log.h" 14 #include "media/base/media_log.h"
15 #include "media/base/video_renderer.h"
15 #include "media/filters/audio_renderer_impl.h" 16 #include "media/filters/audio_renderer_impl.h"
17 #include "media/filters/renderer_impl.h"
16 #include "media/mojo/services/mojo_demuxer_stream_adapter.h" 18 #include "media/mojo/services/mojo_demuxer_stream_adapter.h"
17 #include "media/mojo/services/renderer_config.h" 19 #include "media/mojo/services/renderer_config.h"
18 #include "mojo/application/application_runner_chromium.h" 20 #include "mojo/application/application_runner_chromium.h"
19 #include "mojo/public/c/system/main.h" 21 #include "mojo/public/c/system/main.h"
20 #include "mojo/public/cpp/application/application_connection.h" 22 #include "mojo/public/cpp/application/application_connection.h"
21 #include "mojo/public/cpp/application/application_delegate.h" 23 #include "mojo/public/cpp/application/application_delegate.h"
22 #include "mojo/public/cpp/application/interface_factory_impl.h" 24 #include "mojo/public/cpp/application/interface_factory_impl.h"
23 25
24 namespace media { 26 namespace media {
25 27
26 // Time interval to update media time. 28 // Time interval to update media time.
27 const int kTimeUpdateIntervalMs = 50; 29 const int kTimeUpdateIntervalMs = 50;
28 30
29 static void LogMediaSourceError(const scoped_refptr<MediaLog>& media_log, 31 static void LogMediaSourceError(const scoped_refptr<MediaLog>& media_log,
30 const std::string& error) { 32 const std::string& error) {
31 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); 33 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
32 } 34 }
33 35
34 static base::TimeDelta TimeUpdateInterval() { 36 // Shim DemuxerStreamProvider wrapper for a single DemuxerStream.
35 return base::TimeDelta::FromMilliseconds(kTimeUpdateIntervalMs); 37 // TODO(dalecurtis): Once we support more than one DemuxerStream we'll need a
36 } 38 // more complicated shim which can handle a mojo::Array<DemuxerStream>.
39 class DemuxerStreamProviderShim : public DemuxerStreamProvider {
40 public:
41 DemuxerStreamProviderShim(scoped_ptr<MojoDemuxerStreamAdapter> stream)
42 : stream_(stream.Pass()) {}
43
44 ~DemuxerStreamProviderShim() override {}
45
46 DemuxerStream* GetStream(DemuxerStream::Type type) override {
47 return type != stream_->type() ? nullptr : stream_.get();
48 };
49
50 Liveness GetLiveness() const override {
51 return DemuxerStreamProvider::LIVENESS_UNKNOWN;
52 }
53
54 private:
55 scoped_ptr<MojoDemuxerStreamAdapter> stream_;
56
57 DISALLOW_COPY_AND_ASSIGN(DemuxerStreamProviderShim);
58 };
37 59
38 class MojoRendererApplication 60 class MojoRendererApplication
39 : public mojo::ApplicationDelegate, 61 : public mojo::ApplicationDelegate,
40 public mojo::InterfaceFactory<mojo::MediaRenderer> { 62 public mojo::InterfaceFactory<mojo::MediaRenderer> {
41 public: 63 public:
42 // mojo::ApplicationDelegate implementation. 64 // mojo::ApplicationDelegate implementation.
43 bool ConfigureIncomingConnection( 65 bool ConfigureIncomingConnection(
44 mojo::ApplicationConnection* connection) override { 66 mojo::ApplicationConnection* connection) override {
45 connection->AddService(this); 67 connection->AddService(this);
46 return true; 68 return true;
47 } 69 }
48 70
49 // mojo::InterfaceFactory<mojo::MediaRenderer> implementation. 71 // mojo::InterfaceFactory<mojo::MediaRenderer> implementation.
50 void Create(mojo::ApplicationConnection* connection, 72 void Create(mojo::ApplicationConnection* connection,
51 mojo::InterfaceRequest<mojo::MediaRenderer> request) override { 73 mojo::InterfaceRequest<mojo::MediaRenderer> request) override {
52 mojo::BindToRequest(new MojoRendererService(connection), &request); 74 mojo::BindToRequest(new MojoRendererService(connection), &request);
53 } 75 }
54 }; 76 };
55 77
56 // TODO(xhwang): This class looks insanely similar to RendererImpl. We should 78 static void MojoTrampoline(const mojo::Closure& closure) {
57 // really host a Renderer in this class instead of a AudioRenderer. 79 closure.Run();
80 }
58 81
59 MojoRendererService::MojoRendererService( 82 MojoRendererService::MojoRendererService(
60 mojo::ApplicationConnection* connection) 83 mojo::ApplicationConnection* connection)
61 : state_(STATE_UNINITIALIZED), 84 : state_(STATE_UNINITIALIZED),
62 time_source_(NULL), 85 last_media_time_usec_(0),
63 time_ticking_(false),
64 ended_(false),
65 weak_factory_(this), 86 weak_factory_(this),
66 weak_this_(weak_factory_.GetWeakPtr()) { 87 weak_this_(weak_factory_.GetWeakPtr()) {
67 DVLOG(1) << __FUNCTION__; 88 DVLOG(1) << __FUNCTION__;
68 89
69 scoped_refptr<base::SingleThreadTaskRunner> runner( 90 scoped_refptr<base::SingleThreadTaskRunner> task_runner(
70 base::MessageLoop::current()->task_runner()); 91 base::MessageLoop::current()->task_runner());
71 scoped_refptr<MediaLog> media_log(new MediaLog()); 92 scoped_refptr<MediaLog> media_log(new MediaLog());
72 RendererConfig* renderer_config = RendererConfig::Get(); 93 RendererConfig* renderer_config = RendererConfig::Get();
73 audio_renderer_sink_ = renderer_config->GetAudioRendererSink(); 94 audio_renderer_sink_ = renderer_config->GetAudioRendererSink();
74 95
75 audio_renderer_.reset(new AudioRendererImpl( 96 scoped_ptr<AudioRenderer> audio_renderer(new AudioRendererImpl(
76 runner, 97 task_runner,
77 audio_renderer_sink_.get(), 98 audio_renderer_sink_.get(),
78 renderer_config->GetAudioDecoders( 99 renderer_config->GetAudioDecoders(
79 runner, base::Bind(&LogMediaSourceError, media_log)) 100 task_runner,
80 .Pass(), 101 base::Bind(&LogMediaSourceError, media_log)).Pass(),
81 SetDecryptorReadyCB(), 102 SetDecryptorReadyCB(),
82 renderer_config->GetAudioHardwareConfig(), 103 renderer_config->GetAudioHardwareConfig(),
83 media_log)); 104 media_log));
105 scoped_ptr<VideoRenderer> video_renderer(nullptr);
106
107 // Create renderer.
108 renderer_.reset(new RendererImpl(
109 task_runner, audio_renderer.Pass(), video_renderer.Pass()));
84 } 110 }
85 111
86 MojoRendererService::~MojoRendererService() { 112 MojoRendererService::~MojoRendererService() {
87 } 113 }
88 114
89 void MojoRendererService::Initialize(mojo::DemuxerStreamPtr stream, 115 void MojoRendererService::Initialize(mojo::DemuxerStreamPtr stream,
90 const mojo::Callback<void()>& callback) { 116 const mojo::Closure& callback) {
91 DVLOG(1) << __FUNCTION__; 117 DVLOG(1) << __FUNCTION__;
92 DCHECK_EQ(state_, STATE_UNINITIALIZED) << state_; 118 DCHECK_EQ(state_, STATE_UNINITIALIZED);
93 DCHECK(client()); 119 DCHECK(client());
94 120
95 init_cb_ = callback;
96 state_ = STATE_INITIALIZING; 121 state_ = STATE_INITIALIZING;
97 stream_.reset(new MojoDemuxerStreamAdapter( 122 stream_provider_.reset(new DemuxerStreamProviderShim(
98 stream.Pass(), 123 make_scoped_ptr(new MojoDemuxerStreamAdapter(
99 base::Bind(&MojoRendererService::OnStreamReady, weak_this_))); 124 stream.Pass(),
125 base::Bind(&MojoRendererService::OnStreamReady,
126 weak_this_,
127 callback))).Pass()));
100 } 128 }
101 129
102 void MojoRendererService::Flush(const mojo::Callback<void()>& callback) { 130 void MojoRendererService::Flush(const mojo::Closure& callback) {
103 DVLOG(2) << __FUNCTION__; 131 DVLOG(2) << __FUNCTION__;
104 DCHECK_EQ(state_, STATE_PLAYING) << state_; 132 DCHECK_EQ(state_, STATE_PLAYING);
105 133
106 state_ = STATE_FLUSHING; 134 state_ = STATE_FLUSHING;
107 if (time_ticking_) 135 time_update_timer_.Reset();
108 PausePlayback(); 136 renderer_->Flush(base::Bind(&MojoTrampoline, callback));
109
110 // TODO(xhwang): This is not completed. Finish the flushing path.
111 NOTIMPLEMENTED();
112 } 137 }
113 138
114 void MojoRendererService::StartPlayingFrom(int64_t time_delta_usec) { 139 void MojoRendererService::StartPlayingFrom(int64_t time_delta_usec) {
115 DVLOG(2) << __FUNCTION__ << ": " << time_delta_usec; 140 DVLOG(2) << __FUNCTION__ << ": " << time_delta_usec;
116 base::TimeDelta time = base::TimeDelta::FromMicroseconds(time_delta_usec); 141 renderer_->StartPlayingFrom(
117 time_source_->SetMediaTime(time); 142 base::TimeDelta::FromMicroseconds(time_delta_usec));
118 audio_renderer_->StartPlaying(); 143 SchedulePeriodicMediaTimeUpdates();
119 } 144 }
120 145
121 void MojoRendererService::SetPlaybackRate(float playback_rate) { 146 void MojoRendererService::SetPlaybackRate(float playback_rate) {
122 DVLOG(2) << __FUNCTION__ << ": " << playback_rate; 147 DVLOG(2) << __FUNCTION__ << ": " << playback_rate;
123 148 DCHECK_EQ(state_, STATE_PLAYING);
124 // Playback rate changes are only carried out while playing. 149 renderer_->SetPlaybackRate(playback_rate);
125 if (state_ != STATE_PLAYING)
126 return;
127
128 time_source_->SetPlaybackRate(playback_rate);
129 } 150 }
130 151
131 void MojoRendererService::SetVolume(float volume) { 152 void MojoRendererService::SetVolume(float volume) {
132 if (audio_renderer_) 153 renderer_->SetVolume(volume);
133 audio_renderer_->SetVolume(volume);
134 } 154 }
135 155
136 void MojoRendererService::OnStreamReady() { 156 void MojoRendererService::OnStreamReady(const mojo::Closure& callback) {
137 DCHECK_EQ(state_, STATE_INITIALIZING) << state_; 157 DCHECK_EQ(state_, STATE_INITIALIZING);
138 audio_renderer_->Initialize( 158
139 stream_.get(), 159 renderer_->Initialize(
140 base::Bind(&MojoRendererService::OnAudioRendererInitializeDone, 160 stream_provider_.get(),
141 weak_this_), 161 base::Bind(
162 &MojoRendererService::OnRendererInitializeDone, weak_this_, callback),
142 base::Bind(&MojoRendererService::OnUpdateStatistics, weak_this_), 163 base::Bind(&MojoRendererService::OnUpdateStatistics, weak_this_),
143 base::Bind(&MojoRendererService::OnBufferingStateChanged, weak_this_), 164 base::Bind(&MojoRendererService::OnRendererEnded, weak_this_),
144 base::Bind(&MojoRendererService::OnAudioRendererEnded, weak_this_), 165 base::Bind(&MojoRendererService::OnError, weak_this_),
145 base::Bind(&MojoRendererService::OnError, weak_this_)); 166 base::Bind(&MojoRendererService::OnBufferingStateChanged, weak_this_));
146 } 167 }
147 168
148 void MojoRendererService::OnAudioRendererInitializeDone(PipelineStatus status) { 169 void MojoRendererService::OnRendererInitializeDone(
149 DVLOG(1) << __FUNCTION__ << ": " << status; 170 const mojo::Closure& callback) {
150 DCHECK_EQ(state_, STATE_INITIALIZING) << state_; 171 DVLOG(1) << __FUNCTION__;
151 172
152 if (status != PIPELINE_OK) { 173 if (state_ == STATE_ERROR) {
153 state_ = STATE_ERROR; 174 renderer_.reset();
154 audio_renderer_.reset(); 175 } else {
155 client()->OnError(); 176 DCHECK_EQ(state_, STATE_INITIALIZING);
156 init_cb_.Run(); 177 state_ = STATE_PLAYING;
157 init_cb_.reset();
158 return;
159 } 178 }
160 179
161 time_source_ = audio_renderer_->GetTimeSource(); 180 callback.Run();
162
163 state_ = STATE_PLAYING;
164 init_cb_.Run();
165 init_cb_.reset();
166 } 181 }
167 182
168 void MojoRendererService::OnUpdateStatistics(const PipelineStatistics& stats) { 183 void MojoRendererService::OnUpdateStatistics(const PipelineStatistics& stats) {
169 NOTIMPLEMENTED();
170 } 184 }
171 185
172 void MojoRendererService::UpdateMediaTime() { 186 void MojoRendererService::UpdateMediaTime(bool force) {
173 uint64_t media_time = time_source_->CurrentMediaTime().InMicroseconds(); 187 const uint64_t media_time = renderer_->GetMediaTime().InMicroseconds();
188 if (!force && media_time == last_media_time_usec_)
189 return;
190
174 client()->OnTimeUpdate(media_time, media_time); 191 client()->OnTimeUpdate(media_time, media_time);
192 last_media_time_usec_ = media_time;
175 } 193 }
176 194
177 void MojoRendererService::SchedulePeriodicMediaTimeUpdates() { 195 void MojoRendererService::SchedulePeriodicMediaTimeUpdates() {
178 // Update media time immediately. 196 UpdateMediaTime(true);
179 UpdateMediaTime();
180
181 // Then setup periodic time update.
182 time_update_timer_.Start( 197 time_update_timer_.Start(
183 FROM_HERE, 198 FROM_HERE,
184 TimeUpdateInterval(), 199 base::TimeDelta::FromMilliseconds(kTimeUpdateIntervalMs),
185 base::Bind(&MojoRendererService::UpdateMediaTime, weak_this_)); 200 base::Bind(&MojoRendererService::UpdateMediaTime, weak_this_, false));
186 } 201 }
187 202
188 void MojoRendererService::OnBufferingStateChanged( 203 void MojoRendererService::OnBufferingStateChanged(
189 media::BufferingState new_buffering_state) { 204 BufferingState new_buffering_state) {
190 DVLOG(2) << __FUNCTION__ << "(" << buffering_state_ << ", " 205 DVLOG(2) << __FUNCTION__ << "(" << new_buffering_state << ") ";
191 << new_buffering_state << ") "; 206 client()->OnBufferingStateChange(
192 bool was_waiting_for_enough_data = WaitingForEnoughData(); 207 static_cast<mojo::BufferingState>(new_buffering_state));
193
194 buffering_state_ = new_buffering_state;
195
196 // Renderer underflowed.
197 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
198 PausePlayback();
199 // TODO(xhwang): Notify client of underflow condition.
200 return;
201 }
202
203 // Renderer prerolled.
204 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
205 StartPlayback();
206 client()->OnBufferingStateChange(
207 static_cast<mojo::BufferingState>(new_buffering_state));
208 return;
209 }
210 } 208 }
211 209
212 void MojoRendererService::OnAudioRendererEnded() { 210 void MojoRendererService::OnRendererEnded() {
213 DVLOG(1) << __FUNCTION__; 211 DVLOG(1) << __FUNCTION__;
214
215 if (state_ != STATE_PLAYING)
216 return;
217
218 DCHECK(!ended_);
219 ended_ = true;
220
221 if (time_ticking_)
222 PausePlayback();
223
224 client()->OnEnded(); 212 client()->OnEnded();
213 time_update_timer_.Reset();
225 } 214 }
226 215
227 void MojoRendererService::OnError(PipelineStatus error) { 216 void MojoRendererService::OnError(PipelineStatus error) {
217 DVLOG(1) << __FUNCTION__;
218 state_ = STATE_ERROR;
228 client()->OnError(); 219 client()->OnError();
229 } 220 }
230 221
231 bool MojoRendererService::WaitingForEnoughData() const {
232 DCHECK(audio_renderer_);
233
234 return state_ == STATE_PLAYING && buffering_state_ != BUFFERING_HAVE_ENOUGH;
235 }
236
237 void MojoRendererService::StartPlayback() {
238 DVLOG(1) << __FUNCTION__;
239 DCHECK_EQ(state_, STATE_PLAYING);
240 DCHECK(!time_ticking_);
241 DCHECK(!WaitingForEnoughData());
242
243 time_ticking_ = true;
244 time_source_->StartTicking();
245
246 SchedulePeriodicMediaTimeUpdates();
247 }
248
249 void MojoRendererService::PausePlayback() {
250 DVLOG(1) << __FUNCTION__;
251 DCHECK(time_ticking_);
252 switch (state_) {
253 case STATE_PLAYING:
254 DCHECK(ended_ || WaitingForEnoughData())
255 << "Playback should only pause due to ending or underflowing";
256 break;
257
258 case STATE_FLUSHING:
259 // It's OK to pause playback when flushing.
260 break;
261
262 case STATE_UNINITIALIZED:
263 case STATE_INITIALIZING:
264 case STATE_ERROR:
265 NOTREACHED() << "Invalid state: " << state_;
266 break;
267 }
268
269 time_ticking_ = false;
270 time_source_->StopTicking();
271
272 // Cancel repeating time update timer and update the current media time.
273 time_update_timer_.Stop();
274 UpdateMediaTime();
275 }
276
277 } // namespace media 222 } // namespace media
278 223
279 MojoResult MojoMain(MojoHandle shell_handle) { 224 MojoResult MojoMain(MojoHandle shell_handle) {
280 mojo::ApplicationRunnerChromium runner(new media::MojoRendererApplication); 225 mojo::ApplicationRunnerChromium runner(new media::MojoRendererApplication);
281 return runner.Run(shell_handle); 226 return runner.Run(shell_handle);
282 } 227 }
OLDNEW
« no previous file with comments | « media/mojo/services/mojo_renderer_service.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698