9ed903f0a31e40ea4fffc01cad5a26605888ed05
[platform/framework/web/crosswalk.git] / src / media / mojo / services / mojo_renderer_impl.cc
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
3 // found in the LICENSE file.
4
5 #include "media/mojo/services/mojo_renderer_impl.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "media/base/bind_to_current_loop.h"
12 #include "media/base/demuxer_stream_provider.h"
13 #include "media/mojo/services/mojo_demuxer_stream_impl.h"
14 #include "mojo/public/cpp/application/connect.h"
15 #include "mojo/public/cpp/bindings/interface_impl.h"
16 #include "mojo/public/interfaces/application/service_provider.mojom.h"
17
18 namespace media {
19
20 MojoRendererImpl::MojoRendererImpl(
21     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
22     mojo::ServiceProvider* audio_renderer_provider)
23     : task_runner_(task_runner),
24       weak_factory_(this) {
25   DVLOG(1) << __FUNCTION__;
26   // For now we only support audio and there must be a provider.
27   DCHECK(audio_renderer_provider);
28   mojo::ConnectToService(audio_renderer_provider, &remote_audio_renderer_);
29   remote_audio_renderer_.set_client(this);
30 }
31
32 MojoRendererImpl::~MojoRendererImpl() {
33   DVLOG(1) << __FUNCTION__;
34   DCHECK(task_runner_->BelongsToCurrentThread());
35   // Connection to |remote_audio_renderer_| will error-out here.
36 }
37
38 void MojoRendererImpl::Initialize(
39     DemuxerStreamProvider* demuxer_stream_provider,
40     const base::Closure& init_cb,
41     const StatisticsCB& statistics_cb,
42     const base::Closure& ended_cb,
43     const PipelineStatusCB& error_cb,
44     const BufferingStateCB& buffering_state_cb) {
45   DVLOG(1) << __FUNCTION__;
46   DCHECK(task_runner_->BelongsToCurrentThread());
47   DCHECK(demuxer_stream_provider);
48
49   demuxer_stream_provider_ = demuxer_stream_provider;
50   // |init_cb| can be called on other thread.
51   init_cb_ = init_cb;
52   ended_cb_ = ended_cb;
53   error_cb_ = error_cb;
54   buffering_state_cb_ = buffering_state_cb;
55
56   // Create audio and video mojo::DemuxerStream and bind its lifetime to the
57   // pipe.
58   DemuxerStream* const audio =
59       demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO);
60   DemuxerStream* const video =
61       demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO);
62
63   mojo::DemuxerStreamPtr audio_stream;
64   if (audio)
65     mojo::BindToProxy(new MojoDemuxerStreamImpl(audio), &audio_stream);
66
67   mojo::DemuxerStreamPtr video_stream;
68   if (video)
69     mojo::BindToProxy(new MojoDemuxerStreamImpl(video), &video_stream);
70
71   remote_audio_renderer_->Initialize(
72       audio_stream.Pass(),
73       video_stream.Pass(),
74       BindToCurrentLoop(base::Bind(&MojoRendererImpl::OnInitialized,
75                                    weak_factory_.GetWeakPtr())));
76 }
77
78 void MojoRendererImpl::Flush(const base::Closure& flush_cb) {
79   DVLOG(2) << __FUNCTION__;
80   DCHECK(task_runner_->BelongsToCurrentThread());
81   remote_audio_renderer_->Flush(flush_cb);
82 }
83
84 void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time) {
85   DVLOG(2) << __FUNCTION__;
86   DCHECK(task_runner_->BelongsToCurrentThread());
87
88   {
89     base::AutoLock auto_lock(lock_);
90     time_ = time;
91   }
92
93   remote_audio_renderer_->StartPlayingFrom(time.InMicroseconds());
94 }
95
96 void MojoRendererImpl::SetPlaybackRate(float playback_rate) {
97   DVLOG(2) << __FUNCTION__;
98   DCHECK(task_runner_->BelongsToCurrentThread());
99   remote_audio_renderer_->SetPlaybackRate(playback_rate);
100 }
101
102 void MojoRendererImpl::SetVolume(float volume) {
103   DVLOG(2) << __FUNCTION__;
104   DCHECK(task_runner_->BelongsToCurrentThread());
105   remote_audio_renderer_->SetVolume(volume);
106 }
107
108 base::TimeDelta MojoRendererImpl::GetMediaTime() {
109   base::AutoLock auto_lock(lock_);
110   DVLOG(3) << __FUNCTION__ << ": " << time_.InMilliseconds() << " ms";
111   return time_;
112 }
113
114 bool MojoRendererImpl::HasAudio() {
115   DVLOG(1) << __FUNCTION__;
116   DCHECK(task_runner_->BelongsToCurrentThread());
117   DCHECK(remote_audio_renderer_.get());  // We always bind the renderer.
118   return !!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO);
119 }
120
121 bool MojoRendererImpl::HasVideo() {
122   DVLOG(1) << __FUNCTION__;
123   DCHECK(task_runner_->BelongsToCurrentThread());
124   return !!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO);
125 }
126
127 void MojoRendererImpl::SetCdm(MediaKeys* cdm) {
128   DVLOG(1) << __FUNCTION__;
129   DCHECK(task_runner_->BelongsToCurrentThread());
130   NOTIMPLEMENTED();
131 }
132
133 void MojoRendererImpl::OnTimeUpdate(int64_t time_usec, int64_t max_time_usec) {
134   DVLOG(3) << __FUNCTION__ << ": " << time_usec << ", " << max_time_usec;
135
136   if (!task_runner_->BelongsToCurrentThread()) {
137     task_runner_->PostTask(FROM_HERE,
138                            base::Bind(&MojoRendererImpl::OnTimeUpdate,
139                                       weak_factory_.GetWeakPtr(),
140                                       time_usec,
141                                       max_time_usec));
142     return;
143   }
144
145   base::AutoLock auto_lock(lock_);
146   time_ = base::TimeDelta::FromMicroseconds(time_usec);
147   max_time_ = base::TimeDelta::FromMicroseconds(max_time_usec);
148 }
149
150 void MojoRendererImpl::OnBufferingStateChange(mojo::BufferingState state) {
151   DVLOG(2) << __FUNCTION__;
152
153   if (!task_runner_->BelongsToCurrentThread()) {
154     task_runner_->PostTask(FROM_HERE,
155                            base::Bind(&MojoRendererImpl::OnBufferingStateChange,
156                                       weak_factory_.GetWeakPtr(),
157                                       state));
158     return;
159   }
160
161   buffering_state_cb_.Run(static_cast<media::BufferingState>(state));
162 }
163
164 void MojoRendererImpl::OnEnded() {
165   DVLOG(1) << __FUNCTION__;
166
167   if (!task_runner_->BelongsToCurrentThread()) {
168     task_runner_->PostTask(
169         FROM_HERE,
170         base::Bind(&MojoRendererImpl::OnEnded, weak_factory_.GetWeakPtr()));
171     return;
172   }
173
174   base::ResetAndReturn(&ended_cb_).Run();
175 }
176
177 void MojoRendererImpl::OnError() {
178   DVLOG(1) << __FUNCTION__;
179
180   if (!task_runner_->BelongsToCurrentThread()) {
181     task_runner_->PostTask(
182         FROM_HERE,
183         base::Bind(&MojoRendererImpl::OnError, weak_factory_.GetWeakPtr()));
184     return;
185   }
186
187   // TODO(tim): Should we plumb error code from remote renderer?
188   // http://crbug.com/410451.
189   if (init_cb_.is_null())  // We have initialized already.
190     error_cb_.Run(PIPELINE_ERROR_DECODE);
191   else
192     error_cb_.Run(PIPELINE_ERROR_COULD_NOT_RENDER);
193 }
194
195 void MojoRendererImpl::OnInitialized() {
196   DVLOG(1) << __FUNCTION__;
197   DCHECK(task_runner_->BelongsToCurrentThread());
198   DCHECK(!init_cb_.is_null());
199
200   base::ResetAndReturn(&init_cb_).Run();
201 }
202
203 }  // namespace media