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

Side by Side Diff: chromecast/media/audio/cast_audio_output_stream.cc

Issue 1372393007: [Chromecast] Upgrade to new CMA backend API (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Created 5 years, 2 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "chromecast/media/audio/cast_audio_output_stream.h" 5 #include "chromecast/media/audio/cast_audio_output_stream.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
8 #include "base/synchronization/waitable_event.h" 9 #include "base/synchronization/waitable_event.h"
9 #include "base/threading/thread_checker.h" 10 #include "base/threading/thread_checker.h"
10 #include "chromecast/base/metrics/cast_metrics_helper.h" 11 #include "chromecast/base/metrics/cast_metrics_helper.h"
11 #include "chromecast/media/audio/cast_audio_manager.h" 12 #include "chromecast/media/audio/cast_audio_manager.h"
12 #include "chromecast/media/base/media_message_loop.h" 13 #include "chromecast/media/base/media_message_loop.h"
13 #include "chromecast/media/cma/base/cast_decoder_buffer_impl.h" 14 #include "chromecast/media/cma/base/cast_decoder_buffer_impl.h"
14 #include "chromecast/media/cma/base/decoder_buffer_adapter.h" 15 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
15 #include "chromecast/media/cma/pipeline/frame_status_cb_impl.h"
16 #include "chromecast/public/media/audio_pipeline_device.h"
17 #include "chromecast/public/media/decoder_config.h" 16 #include "chromecast/public/media/decoder_config.h"
18 #include "chromecast/public/media/decrypt_context.h" 17 #include "chromecast/public/media/decrypt_context.h"
19 #include "chromecast/public/media/media_clock_device.h"
20 #include "chromecast/public/media/media_pipeline_backend.h" 18 #include "chromecast/public/media/media_pipeline_backend.h"
21 #include "media/base/bind_to_current_loop.h" 19 #include "media/base/bind_to_current_loop.h"
22 #include "media/base/decoder_buffer.h" 20 #include "media/base/decoder_buffer.h"
23 21
24 namespace chromecast { 22 namespace chromecast {
25 namespace media { 23 namespace media {
24 namespace {
26 25
27 namespace { 26 MediaPipelineBackend::AudioDecoder* InitializeBackend(
28 bool InitClockDevice(MediaClockDevice* clock_device) { 27 const ::media::AudioParameters& audio_params,
29 DCHECK(clock_device); 28 MediaPipelineBackend* backend,
30 DCHECK_EQ(clock_device->GetState(), MediaClockDevice::kStateUninitialized); 29 MediaPipelineBackend::Delegate* delegate) {
30 DCHECK(backend);
31 DCHECK(delegate);
31 32
32 if (!clock_device->SetState(media::MediaClockDevice::kStateIdle)) 33 MediaPipelineBackend::AudioDecoder* decoder = backend->CreateAudioDecoder();
33 return false; 34 if (!decoder)
34 35 return nullptr;
35 if (!clock_device->ResetTimeline(0))
36 return false;
37
38 if (!clock_device->SetRate(1.0))
39 return false;
40
41 return true;
42 }
43
44 bool InitAudioDevice(const ::media::AudioParameters& audio_params,
45 AudioPipelineDevice* audio_device) {
46 DCHECK(audio_device);
47 DCHECK_EQ(audio_device->GetState(), AudioPipelineDevice::kStateUninitialized);
48 36
49 AudioConfig audio_config; 37 AudioConfig audio_config;
50 audio_config.codec = kCodecPCM; 38 audio_config.codec = kCodecPCM;
51 audio_config.sample_format = kSampleFormatS16; 39 audio_config.sample_format = kSampleFormatS16;
52 audio_config.bytes_per_channel = audio_params.bits_per_sample() / 8; 40 audio_config.bytes_per_channel = audio_params.bits_per_sample() / 8;
53 audio_config.channel_number = audio_params.channels(); 41 audio_config.channel_number = audio_params.channels();
54 audio_config.samples_per_second = audio_params.sample_rate(); 42 audio_config.samples_per_second = audio_params.sample_rate();
55 audio_config.extra_data = nullptr; 43 audio_config.extra_data = nullptr;
56 audio_config.extra_data_size = 0; 44 audio_config.extra_data_size = 0;
57 audio_config.is_encrypted = false; 45 audio_config.is_encrypted = false;
58 if (!audio_device->SetConfig(audio_config))
59 return false;
60 46
61 if (!audio_device->SetState(AudioPipelineDevice::kStateIdle)) 47 if (!decoder->SetConfig(audio_config))
62 return false; 48 return nullptr;
63 49
64 return true; 50 if (!backend->Initialize(delegate))
51 return nullptr;
52
53 return decoder;
65 } 54 }
55
66 } // namespace 56 } // namespace
67 57
68 // Backend represents a MediaPipelineBackend adapter that runs on cast 58 // Backend represents a MediaPipelineBackend adapter that runs on cast
69 // media thread (media::MediaMessageLoop::GetTaskRunner). 59 // media thread (media::MediaMessageLoop::GetTaskRunner).
70 // It can be created and destroyed on any thread, but all other member functions 60 // It can be created and destroyed on any thread, but all other member functions
71 // must be called on a single thread. 61 // must be called on a single thread.
72 class CastAudioOutputStream::Backend { 62 class CastAudioOutputStream::Backend : public MediaPipelineBackend::Delegate {
73 public: 63 public:
74 typedef base::Callback<void(bool)> PushFrameCompletionCallback; 64 typedef base::Callback<void(bool)> PushBufferCompletionCallback;
75 65
76 Backend(const ::media::AudioParameters& audio_params) 66 Backend(const ::media::AudioParameters& audio_params)
77 : audio_params_(audio_params) { 67 : audio_params_(audio_params),
68 decoder_(nullptr),
69 first_start_(true),
70 error_(false) {
78 thread_checker_.DetachFromThread(); 71 thread_checker_.DetachFromThread();
79 } 72 }
80 ~Backend() {} 73 ~Backend() override {}
81 74
82 void Open(CastAudioManager* audio_manager, 75 void Open(CastAudioManager* audio_manager,
83 bool* success, 76 bool* success,
slan 2015/10/06 19:33:59 nit: DCHECK all raw input
kmackay 2015/10/06 21:44:55 Done.
84 base::WaitableEvent* completion_event) { 77 base::WaitableEvent* completion_event) {
85 DCHECK(thread_checker_.CalledOnValidThread()); 78 DCHECK(thread_checker_.CalledOnValidThread());
86 DCHECK(backend_ == nullptr); 79 DCHECK(backend_ == nullptr);
87 80
88 scoped_ptr<MediaPipelineBackend> pipeline_backend = 81 backend_ = audio_manager->CreateMediaPipelineBackend();
slan 2015/10/06 19:34:00 Can't an AudioOuput stream be created and opened a
kmackay 2015/10/06 21:44:55 A whole new backend is created for each stream.
slan 2015/10/06 22:15:05 Duh, thank you.
89 audio_manager->CreateMediaPipelineBackend(); 82 if (backend_)
90 if (pipeline_backend && InitClockDevice(pipeline_backend->GetClock()) && 83 decoder_ = InitializeBackend(audio_params_, backend_.get(), this);
91 InitAudioDevice(audio_params_, pipeline_backend->GetAudio())) { 84 *success = decoder_ != nullptr;
92 backend_ = pipeline_backend.Pass();
93 }
94 *success = backend_ != nullptr;
95 completion_event->Signal(); 85 completion_event->Signal();
96 } 86 }
97 87
98 void Close() { 88 void Close() {
99 DCHECK(thread_checker_.CalledOnValidThread()); 89 DCHECK(thread_checker_.CalledOnValidThread());
100 90
101 if (backend_) { 91 if (backend_)
102 backend_->GetClock()->SetState(MediaClockDevice::kStateIdle); 92 backend_->Stop();
103 backend_->GetAudio()->SetState(AudioPipelineDevice::kStateIdle);
104 }
105 backend_.reset(); 93 backend_.reset();
106 } 94 }
107 95
108 void Start() { 96 void Start() {
109 DCHECK(thread_checker_.CalledOnValidThread()); 97 DCHECK(thread_checker_.CalledOnValidThread());
110 98
111 MediaClockDevice* clock_device = backend_->GetClock(); 99 if (first_start_)
112 clock_device->SetState(MediaClockDevice::kStateRunning); 100 backend_->Start(0);
slan 2015/10/06 19:34:00 DCHECK backend_ before use to be defensive. Here a
kmackay 2015/10/06 21:44:55 Done.
113 clock_device->SetRate(1.0f); 101 else
114 102 backend_->Resume();
115 AudioPipelineDevice* audio_device = backend_->GetAudio();
116 audio_device->SetState(AudioPipelineDevice::kStateRunning);
117 } 103 }
118 104
119 void Stop() { 105 void Stop() {
120 DCHECK(thread_checker_.CalledOnValidThread()); 106 DCHECK(thread_checker_.CalledOnValidThread());
121 107
122 MediaClockDevice* clock_device = backend_->GetClock(); 108 backend_->Pause();
slan 2015/10/06 19:34:00 DCHECK backend_ before use
kmackay 2015/10/06 21:44:55 Done.
123 clock_device->SetRate(0.0f); 109 first_start_ = false;
124 } 110 }
125 111
126 void PushFrame(scoped_refptr<media::DecoderBufferBase> decoder_buffer, 112 void PushBuffer(scoped_refptr<media::DecoderBufferBase> decoder_buffer,
127 const PushFrameCompletionCallback& completion_cb) { 113 const PushBufferCompletionCallback& completion_cb) {
128 DCHECK(thread_checker_.CalledOnValidThread()); 114 DCHECK(thread_checker_.CalledOnValidThread());
115 DCHECK(decoder_);
116 DCHECK(completion_cb_.is_null());
117 if (error_) {
118 completion_cb.Run(false);
119 return;
120 }
129 121
130 AudioPipelineDevice* audio_device = backend_->GetAudio(); 122 if (backend_buffer_)
131 MediaComponentDevice::FrameStatus status = 123 backend_buffer_->set_buffer(decoder_buffer);
132 audio_device->PushFrame(nullptr, // decrypt_context 124 else
133 new CastDecoderBufferImpl(decoder_buffer), 125 backend_buffer_.reset(new CastDecoderBufferImpl(decoder_buffer));
134 new media::FrameStatusCBImpl(base::Bind(
135 &Backend::OnPushFrameStatus,
136 base::Unretained(this), completion_cb)));
137 126
138 if (status != MediaComponentDevice::kFramePending) 127 MediaPipelineBackend::BufferStatus status =
139 OnPushFrameStatus(completion_cb, status); 128 decoder_->PushBuffer(nullptr, backend_buffer_.get());
129 completion_cb_ = completion_cb;
130 if (status != MediaPipelineBackend::kBufferPending)
131 OnPushBufferComplete(decoder_, status);
140 } 132 }
141 133
142 void SetVolume(double volume) { 134 void SetVolume(double volume) {
143 DCHECK(thread_checker_.CalledOnValidThread()); 135 DCHECK(thread_checker_.CalledOnValidThread());
136 decoder_->SetVolume(volume);
slan 2015/10/06 19:34:00 DCHECK(decoder_) before use
kmackay 2015/10/06 21:44:55 Done.
137 }
144 138
145 AudioPipelineDevice* audio_device = backend_->GetAudio(); 139 // MediaPipelineBackend::Delegate implementation
146 audio_device->SetStreamVolumeMultiplier(volume); 140 void OnVideoResolutionChanged(MediaPipelineBackend::Decoder* decoder,
141 const Size& size) override {}
142
143 void OnPushBufferComplete(
144 MediaPipelineBackend::Decoder* decoder,
145 MediaPipelineBackend::BufferStatus status) override {
146 DCHECK(thread_checker_.CalledOnValidThread());
147 DCHECK_NE(status, MediaPipelineBackend::kBufferPending);
148
149 base::ResetAndReturn(&completion_cb_)
150 .Run(status == MediaPipelineBackend::kBufferSuccess);
151 }
152
153 void OnEndOfStream(MediaPipelineBackend::Decoder* decoder) override {}
154
155 void OnDecoderError(MediaPipelineBackend::Decoder* decoder) override {
156 error_ = true;
157 if (!completion_cb_.is_null())
158 OnPushBufferComplete(decoder_, MediaPipelineBackend::kBufferFailed);
147 } 159 }
148 160
149 private: 161 private:
150 void OnPushFrameStatus(const PushFrameCompletionCallback& completion_cb,
151 MediaComponentDevice::FrameStatus status) {
152 DCHECK(thread_checker_.CalledOnValidThread());
153 DCHECK_NE(status, MediaComponentDevice::kFramePending);
154
155 completion_cb.Run(status == MediaComponentDevice::kFrameSuccess);
156 }
157
158 const ::media::AudioParameters audio_params_; 162 const ::media::AudioParameters audio_params_;
159 scoped_ptr<MediaPipelineBackend> backend_; 163 scoped_ptr<MediaPipelineBackend> backend_;
164 MediaPipelineBackend::AudioDecoder* decoder_;
165 PushBufferCompletionCallback completion_cb_;
166 bool first_start_;
167 bool error_;
168 scoped_ptr<CastDecoderBufferImpl> backend_buffer_;
160 base::ThreadChecker thread_checker_; 169 base::ThreadChecker thread_checker_;
161 DISALLOW_COPY_AND_ASSIGN(Backend); 170 DISALLOW_COPY_AND_ASSIGN(Backend);
162 }; 171 };
163 172
164 // CastAudioOutputStream runs on audio thread (AudioManager::GetTaskRunner). 173 // CastAudioOutputStream runs on audio thread (AudioManager::GetTaskRunner).
165 CastAudioOutputStream::CastAudioOutputStream( 174 CastAudioOutputStream::CastAudioOutputStream(
166 const ::media::AudioParameters& audio_params, 175 const ::media::AudioParameters& audio_params,
167 CastAudioManager* audio_manager) 176 CastAudioManager* audio_manager)
168 : audio_params_(audio_params), 177 : audio_params_(audio_params),
169 audio_manager_(audio_manager), 178 audio_manager_(audio_manager),
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 242 DCHECK(audio_task_runner_->BelongsToCurrentThread());
234 DCHECK(source_callback); 243 DCHECK(source_callback);
235 244
236 source_callback_ = source_callback; 245 source_callback_ = source_callback;
237 backend_task_runner_->PostTask( 246 backend_task_runner_->PostTask(
238 FROM_HERE, base::Bind(&Backend::Start, base::Unretained(backend_.get()))); 247 FROM_HERE, base::Bind(&Backend::Start, base::Unretained(backend_.get())));
239 248
240 next_push_time_ = base::TimeTicks::Now(); 249 next_push_time_ = base::TimeTicks::Now();
241 if (!backend_busy_) { 250 if (!backend_busy_) {
242 audio_task_runner_->PostTask(FROM_HERE, 251 audio_task_runner_->PostTask(FROM_HERE,
243 base::Bind(&CastAudioOutputStream::PushFrame, 252 base::Bind(&CastAudioOutputStream::PushBuffer,
244 weak_factory_.GetWeakPtr())); 253 weak_factory_.GetWeakPtr()));
245 } 254 }
246 255
247 metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstAudio(); 256 metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstAudio();
248 } 257 }
249 258
250 void CastAudioOutputStream::Stop() { 259 void CastAudioOutputStream::Stop() {
251 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 260 DCHECK(audio_task_runner_->BelongsToCurrentThread());
252 261
253 source_callback_ = nullptr; 262 source_callback_ = nullptr;
(...skipping 18 matching lines...) Expand all
272 281
273 void CastAudioOutputStream::OnClosed() { 282 void CastAudioOutputStream::OnClosed() {
274 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 283 DCHECK(audio_task_runner_->BelongsToCurrentThread());
275 284
276 VLOG(1) << __FUNCTION__ << " : " << this; 285 VLOG(1) << __FUNCTION__ << " : " << this;
277 // Signal to the manager that we're closed and can be removed. 286 // Signal to the manager that we're closed and can be removed.
278 // This should be the last call in the function as it deletes "this". 287 // This should be the last call in the function as it deletes "this".
279 audio_manager_->ReleaseOutputStream(this); 288 audio_manager_->ReleaseOutputStream(this);
280 } 289 }
281 290
282 void CastAudioOutputStream::PushFrame() { 291 void CastAudioOutputStream::PushBuffer() {
283 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 292 DCHECK(audio_task_runner_->BelongsToCurrentThread());
284 DCHECK(!backend_busy_); 293 DCHECK(!backend_busy_);
285 294
286 if (!source_callback_) 295 if (!source_callback_)
287 return; 296 return;
288 297
289 uint32_t bytes_delay = 0; 298 uint32_t bytes_delay = 0;
290 int frame_count = source_callback_->OnMoreData(audio_bus_.get(), bytes_delay); 299 int frame_count = source_callback_->OnMoreData(audio_bus_.get(), bytes_delay);
291 VLOG(3) << "frames_filled=" << frame_count << " with latency=" << bytes_delay; 300 VLOG(3) << "frames_filled=" << frame_count << " with latency=" << bytes_delay;
292 301
293 DCHECK_EQ(frame_count, audio_bus_->frames()); 302 DCHECK_EQ(frame_count, audio_bus_->frames());
294 DCHECK_EQ(static_cast<int>(decoder_buffer_->data_size()), 303 DCHECK_EQ(static_cast<int>(decoder_buffer_->data_size()),
295 frame_count * audio_params_.GetBytesPerFrame()); 304 frame_count * audio_params_.GetBytesPerFrame());
296 audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8, 305 audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8,
297 decoder_buffer_->writable_data()); 306 decoder_buffer_->writable_data());
298 307
299 auto completion_cb = ::media::BindToCurrentLoop(base::Bind( 308 auto completion_cb = ::media::BindToCurrentLoop(
300 &CastAudioOutputStream::OnPushFrameComplete, weak_factory_.GetWeakPtr())); 309 base::Bind(&CastAudioOutputStream::OnPushBufferComplete,
301 backend_task_runner_->PostTask( 310 weak_factory_.GetWeakPtr()));
302 FROM_HERE, 311 backend_task_runner_->PostTask(FROM_HERE,
303 base::Bind(&Backend::PushFrame, base::Unretained(backend_.get()), 312 base::Bind(&Backend::PushBuffer,
304 decoder_buffer_, completion_cb)); 313 base::Unretained(backend_.get()),
314 decoder_buffer_,
315 completion_cb));
305 backend_busy_ = true; 316 backend_busy_ = true;
306 } 317 }
307 318
308 void CastAudioOutputStream::OnPushFrameComplete(bool success) { 319 void CastAudioOutputStream::OnPushBufferComplete(bool success) {
309 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 320 DCHECK(audio_task_runner_->BelongsToCurrentThread());
310 321
311 backend_busy_ = false; 322 backend_busy_ = false;
312 if (!source_callback_) 323 if (!source_callback_)
313 return; 324 return;
314 325
315 if (!success) { 326 if (!success) {
316 source_callback_->OnError(this); 327 source_callback_->OnError(this);
317 return; 328 return;
318 } 329 }
319 330
320 // Schedule next push frame. 331 // Schedule next push buffer.
321 // Need to account for time spent in pulling and pushing frame as well 332 // Need to account for time spent in pulling and pushing buffer as well
322 // as the imprecision of PostDelayedTask(). 333 // as the imprecision of PostDelayedTask().
323 const base::TimeTicks now = base::TimeTicks::Now(); 334 const base::TimeTicks now = base::TimeTicks::Now();
324 base::TimeDelta delay = next_push_time_ + buffer_duration_ - now; 335 base::TimeDelta delay = next_push_time_ + buffer_duration_ - now;
325 delay = std::max(delay, base::TimeDelta()); 336 delay = std::max(delay, base::TimeDelta());
326 next_push_time_ = now + delay; 337 next_push_time_ = now + delay;
327 338
328 audio_task_runner_->PostDelayedTask( 339 audio_task_runner_->PostDelayedTask(
329 FROM_HERE, 340 FROM_HERE,
330 base::Bind(&CastAudioOutputStream::PushFrame, weak_factory_.GetWeakPtr()), 341 base::Bind(&CastAudioOutputStream::PushBuffer,
342 weak_factory_.GetWeakPtr()),
331 delay); 343 delay);
332 } 344 }
333 345
334 } // namespace media 346 } // namespace media
335 } // namespace chromecast 347 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698