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

Side by Side Diff: chromecast/renderer/media/audio_pipeline_proxy.cc

Issue 814403002: [Chromecast] Add CmaMediaRendererFactory and IPC proxy components (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years 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 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 "chromecast/renderer/media/audio_pipeline_proxy.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/memory/shared_memory.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/threading/thread_checker.h"
12 #include "chromecast/common/media/cma_ipc_common.h"
13 #include "chromecast/common/media/cma_messages.h"
14 #include "chromecast/common/media/shared_memory_chunk.h"
15 #include "chromecast/media/cma/base/buffering_defs.h"
16 #include "chromecast/media/cma/base/cma_logging.h"
17 #include "chromecast/media/cma/base/coded_frame_provider.h"
18 #include "chromecast/media/cma/ipc/media_message_fifo.h"
19 #include "chromecast/media/cma/ipc_streamer/av_streamer_proxy.h"
20 #include "chromecast/media/cma/pipeline/av_pipeline_client.h"
21 #include "chromecast/renderer/media/cma_message_filter_proxy.h"
22 #include "chromecast/renderer/media/media_channel_proxy.h"
23 #include "media/base/bind_to_current_loop.h"
24 #include "media/base/pipeline_status.h"
25
26 namespace chromecast {
27 namespace cma {
28
29 namespace {
30
31 void Noop() {
gunsch 2014/12/20 22:41:33 probably rename to something like "IgnoreResult"
erickung1 2014/12/21 11:10:46 Done.
32 }
33
34 } // namespace
35
36 // AudioPipelineProxyInternal -
37 // This class is not thread safe and should run on the same thread
38 // as the media channel proxy.
39 class AudioPipelineProxyInternal {
40 public:
41 typedef base::Callback<void(scoped_ptr<base::SharedMemory>)> SharedMemCB;
42
43 static void Release(scoped_ptr<AudioPipelineProxyInternal> proxy);
44
45 explicit AudioPipelineProxyInternal(
46 scoped_refptr<MediaChannelProxy> media_channel_proxy);
47 virtual ~AudioPipelineProxyInternal();
48
49 // Notify the other side (browser process) of some activity on the audio pipe.
50 // TODO(damienv): either send an IPC message or write a byte on the
gunsch 2014/12/20 22:41:33 we probably shouldn't be adding any TODO(damienv)
erickung1 2014/12/21 11:10:46 Change to my name first. I checked the code and it
51 // SyncSocket.
52 void NotifyPipeWrite();
53
54 // These functions are almost a one to one correspondence with AudioPipeline
55 // but this is an internal class and there is no reason to derive from
56 // AudioPipeline.
57 void SetClient(const base::Closure& pipe_read_cb,
58 const chromecast::media::AvPipelineClient& client);
59 void CreateAvPipe(const SharedMemCB& shared_mem_cb);
60 void Initialize(const ::media::AudioDecoderConfig& config,
61 const ::media::PipelineStatusCB& status_cb);
62 void SetVolume(float volume);
63
64 private:
65 void Shutdown();
66
67 // Callbacks for CmaMessageFilterHost::AudioDelegate.
68 void OnAvPipeCreated(bool status,
69 base::SharedMemoryHandle shared_mem_handle,
70 base::FileDescriptor socket);
71 void OnStateChanged(::media::PipelineStatus status);
72
73 base::ThreadChecker thread_checker_;
74
75 scoped_refptr<MediaChannelProxy> media_channel_proxy_;
76
77 // Store the callback for a pending state transition.
78 ::media::PipelineStatusCB status_cb_;
79
80 SharedMemCB shared_mem_cb_;
81
82 DISALLOW_COPY_AND_ASSIGN(AudioPipelineProxyInternal);
gunsch 2014/12/20 22:41:33 include base/macros.h
erickung1 2014/12/21 11:10:46 probably don't need it since audio_pipeline_proxy.
83 };
84
85 // static
86 void AudioPipelineProxyInternal::Release(
87 scoped_ptr<AudioPipelineProxyInternal> proxy) {
88 proxy->Shutdown();
89 }
90
91 AudioPipelineProxyInternal::AudioPipelineProxyInternal(
92 scoped_refptr<MediaChannelProxy> media_channel_proxy)
93 : media_channel_proxy_(media_channel_proxy) {
94 DCHECK(media_channel_proxy.get());
95
96 // Creation can be done on a different thread.
97 thread_checker_.DetachFromThread();
98 }
99
100 AudioPipelineProxyInternal::~AudioPipelineProxyInternal() {
101 }
102
103 void AudioPipelineProxyInternal::Shutdown() {
104 DCHECK(thread_checker_.CalledOnValidThread());
105
106 // Remove any callback on AudioPipelineProxyInternal.
107 media_channel_proxy_->SetAudioDelegate(
108 CmaMessageFilterProxy::AudioDelegate());
109 }
110
111 void AudioPipelineProxyInternal::NotifyPipeWrite() {
112 DCHECK(thread_checker_.CalledOnValidThread());
113
114 // TODO(damienv): An alternative way would be to use a dedicated socket for
115 // this event.
116 bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>(
117 new CmaHostMsg_NotifyPipeWrite(
118 media_channel_proxy_->GetId(), chromecast::media::kAudioTrackId)));
119 VLOG_IF(4, !success) << "Sending msg failed";
120 }
121
122 void AudioPipelineProxyInternal::SetClient(
123 const base::Closure& pipe_read_cb,
124 const chromecast::media::AvPipelineClient& client) {
125 DCHECK(thread_checker_.CalledOnValidThread());
126
127 CmaMessageFilterProxy::AudioDelegate delegate;
128 delegate.av_pipe_cb =
129 base::Bind(&AudioPipelineProxyInternal::OnAvPipeCreated,
130 base::Unretained(this));
131 delegate.state_changed_cb =
132 base::Bind(&AudioPipelineProxyInternal::OnStateChanged,
133 base::Unretained(this));
134 delegate.pipe_read_cb = pipe_read_cb;
135 delegate.client = client;
136 bool success = media_channel_proxy_->SetAudioDelegate(delegate);
137 CHECK(success);
138 }
139
140 void AudioPipelineProxyInternal::CreateAvPipe(
141 const SharedMemCB& shared_mem_cb) {
142 DCHECK(thread_checker_.CalledOnValidThread());
143 DCHECK(shared_mem_cb_.is_null());
144 bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>(
145 new CmaHostMsg_CreateAvPipe(
146 media_channel_proxy_->GetId(), chromecast::media::kAudioTrackId,
147 chromecast::media::kAppAudioBufferSize)));
148 if (!success) {
149 shared_mem_cb.Run(scoped_ptr<base::SharedMemory>());
150 return;
151 }
152 shared_mem_cb_ = shared_mem_cb;
153 }
154
155 void AudioPipelineProxyInternal::OnAvPipeCreated(
156 bool success,
157 base::SharedMemoryHandle shared_mem_handle,
158 base::FileDescriptor socket) {
159 DCHECK(thread_checker_.CalledOnValidThread());
160 DCHECK(!shared_mem_cb_.is_null());
161 if (!success) {
162 shared_mem_cb_.Run(scoped_ptr<base::SharedMemory>());
163 return;
164 }
165
166 CHECK(base::SharedMemory::IsHandleValid(shared_mem_handle));
167 shared_mem_cb_.Run(scoped_ptr<base::SharedMemory>(
168 new base::SharedMemory(shared_mem_handle, false)));
169 }
170
171 #define DEFINE_STATE_TRANSITION_1(param_fn, param_msg, param_type1) \
gunsch 2014/12/20 22:41:33 This #define is only used once; this would be clea
erickung1 2014/12/21 11:10:46 Done.
172 void AudioPipelineProxyInternal::param_fn( \
173 const param_type1& arg1, \
174 const ::media::PipelineStatusCB& status_cb) { \
175 DCHECK(thread_checker_.CalledOnValidThread()); \
176 bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>( \
177 new param_msg( \
178 media_channel_proxy_->GetId(), chromecast::media::kAudioTrackId, \
179 arg1))); \
180 if (!success) { \
181 status_cb.Run( \
182 ::media::PIPELINE_ERROR_INITIALIZATION_FAILED); \
183 return; \
184 } \
185 DCHECK(status_cb_.is_null()); \
186 status_cb_ = status_cb; \
187 }
188
189 DEFINE_STATE_TRANSITION_1(Initialize, CmaHostMsg_AudioInitialize,
190 ::media::AudioDecoderConfig)
191
192 void AudioPipelineProxyInternal::SetVolume(float volume) {
193 DCHECK(thread_checker_.CalledOnValidThread());
194 media_channel_proxy_->Send(scoped_ptr<IPC::Message>(
195 new CmaHostMsg_SetVolume(
196 media_channel_proxy_->GetId(),
197 chromecast::media::kAudioTrackId, volume)));
198 }
199
200 void AudioPipelineProxyInternal::OnStateChanged(
201 ::media::PipelineStatus status) {
202 DCHECK(thread_checker_.CalledOnValidThread());
203 DCHECK(!status_cb_.is_null());
204 base::ResetAndReturn(&status_cb_).Run(status);
205 }
206
207
208 #define FORWARD_ON_IO_0(param_fn) \
gunsch 2014/12/20 22:41:33 This #define is also only used once, just unroll i
erickung1 2014/12/21 11:10:46 Done.
209 io_message_loop_proxy_->PostTask( \
210 FROM_HERE, \
211 base::Bind(&AudioPipelineProxyInternal::param_fn, \
212 base::Unretained(proxy_.get())))
213 #define FORWARD_ON_IO_1(param_fn, param_arg1) \
214 io_message_loop_proxy_->PostTask( \
215 FROM_HERE, \
216 base::Bind(&AudioPipelineProxyInternal::param_fn, \
217 base::Unretained(proxy_.get()), (param_arg1)))
218 #define FORWARD_ON_IO_2(param_fn, param_arg1, param_arg2) \
219 io_message_loop_proxy_->PostTask( \
220 FROM_HERE, \
221 base::Bind(&AudioPipelineProxyInternal::param_fn, \
222 base::Unretained(proxy_.get()), (param_arg1), (param_arg2)))
223
224 AudioPipelineProxy::AudioPipelineProxy(
225 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy,
226 scoped_refptr<MediaChannelProxy> media_channel_proxy)
227 : io_message_loop_proxy_(io_message_loop_proxy),
228 proxy_(new AudioPipelineProxyInternal(media_channel_proxy)),
229 audio_streamer_(new chromecast::media::AvStreamerProxy()),
230 weak_factory_(this) {
231 DCHECK(io_message_loop_proxy_.get());
232 weak_this_ = weak_factory_.GetWeakPtr();
233 thread_checker_.DetachFromThread();
234 }
235
236 AudioPipelineProxy::~AudioPipelineProxy() {
237 DCHECK(thread_checker_.CalledOnValidThread());
238 // Release the underlying object on the right thread.
239 io_message_loop_proxy_->PostTask(
240 FROM_HERE,
241 base::Bind(&AudioPipelineProxyInternal::Release, base::Passed(&proxy_)));
242 }
243
244 void AudioPipelineProxy::SetClient(
245 const chromecast::media::AvPipelineClient& client) {
246 DCHECK(thread_checker_.CalledOnValidThread());
247 base::Closure pipe_read_cb = ::media::BindToCurrentLoop(
248 base::Bind(&AudioPipelineProxy::OnPipeRead, weak_this_));
249 FORWARD_ON_IO_2(SetClient, pipe_read_cb, client);
250 }
251
252 void AudioPipelineProxy::Initialize(
253 const ::media::AudioDecoderConfig& config,
254 scoped_ptr<chromecast::media::CodedFrameProvider> frame_provider,
255 const ::media::PipelineStatusCB& status_cb) {
256 CMALOG(chromecast::media::kLogControl) << "AudioPipelineProxy::Initialize";
257 DCHECK(thread_checker_.CalledOnValidThread());
258 audio_streamer_->SetCodedFrameProvider(frame_provider.Pass());
259
260 AudioPipelineProxyInternal::SharedMemCB shared_mem_cb =
261 ::media::BindToCurrentLoop(base::Bind(
262 &AudioPipelineProxy::OnAvPipeCreated, weak_this_,
263 config, status_cb));
264 FORWARD_ON_IO_1(CreateAvPipe, shared_mem_cb);
265 }
266
267 void AudioPipelineProxy::OnAvPipeCreated(
268 const ::media::AudioDecoderConfig& config,
269 const ::media::PipelineStatusCB& status_cb,
270 scoped_ptr<base::SharedMemory> shared_memory) {
271 CMALOG(chromecast::media::kLogControl)
272 << "AudioPipelineProxy::OnAvPipeCreated";
273 DCHECK(thread_checker_.CalledOnValidThread());
274 if (!shared_memory ||
275 !shared_memory->Map(chromecast::media::kAppAudioBufferSize)) {
276 status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
277 return;
278 }
279 CHECK(shared_memory->memory());
280
281 scoped_ptr<chromecast::media::MediaMemoryChunk> shared_memory_chunk(
282 new chromecast::media::SharedMemoryChunk(
283 shared_memory.Pass(), chromecast::media::kAppAudioBufferSize));
284 scoped_ptr<chromecast::media::MediaMessageFifo> audio_pipe(
285 new chromecast::media::MediaMessageFifo(
286 shared_memory_chunk.Pass(), false));
287 audio_pipe->ObserveWriteActivity(
288 base::Bind(&AudioPipelineProxy::OnPipeWrite, weak_this_));
289
290 audio_streamer_->SetMediaMessageFifo(audio_pipe.Pass());
291
292 // Now proceed to the decoder/renderer initialization.
293 FORWARD_ON_IO_2(Initialize, config, status_cb);
294 }
295
296 void AudioPipelineProxy::StartFeeding() {
297 DCHECK(thread_checker_.CalledOnValidThread());
298 DCHECK(audio_streamer_);
299 audio_streamer_->Start();
300 }
301
302 void AudioPipelineProxy::Flush(const base::Closure& done_cb) {
303 DCHECK(thread_checker_.CalledOnValidThread());
304 DCHECK(audio_streamer_);
305 audio_streamer_->StopAndFlush(done_cb);
306 }
307
308 void AudioPipelineProxy::Stop() {
309 DCHECK(thread_checker_.CalledOnValidThread());
310 if (!audio_streamer_)
311 return;
312 audio_streamer_->StopAndFlush(base::Bind(&Noop));
313 }
314
315 void AudioPipelineProxy::SetVolume(float volume) {
316 DCHECK(thread_checker_.CalledOnValidThread());
317 FORWARD_ON_IO_1(SetVolume, volume);
318 }
319
320 void AudioPipelineProxy::OnPipeWrite() {
321 DCHECK(thread_checker_.CalledOnValidThread());
322 FORWARD_ON_IO_0(NotifyPipeWrite);
323 }
324
325 void AudioPipelineProxy::OnPipeRead() {
326 DCHECK(thread_checker_.CalledOnValidThread());
327 if (audio_streamer_)
328 audio_streamer_->OnFifoReadEvent();
329 }
330
331 } // namespace cma
332 } // namespace chromecast
333
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698