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

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: Fix end_to_end test + address slan comments 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,
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);
80 DCHECK(audio_manager);
81 DCHECK(success);
82 DCHECK(completion_event);
87 83
88 scoped_ptr<MediaPipelineBackend> pipeline_backend = 84 backend_ = audio_manager->CreateMediaPipelineBackend();
89 audio_manager->CreateMediaPipelineBackend(); 85 if (backend_)
90 if (pipeline_backend && InitClockDevice(pipeline_backend->GetClock()) && 86 decoder_ = InitializeBackend(audio_params_, backend_.get(), this);
91 InitAudioDevice(audio_params_, pipeline_backend->GetAudio())) { 87 *success = decoder_ != nullptr;
92 backend_ = pipeline_backend.Pass();
93 }
94 *success = backend_ != nullptr;
95 completion_event->Signal(); 88 completion_event->Signal();
96 } 89 }
97 90
98 void Close() { 91 void Close() {
99 DCHECK(thread_checker_.CalledOnValidThread()); 92 DCHECK(thread_checker_.CalledOnValidThread());
100 93
101 if (backend_) { 94 if (backend_)
102 backend_->GetClock()->SetState(MediaClockDevice::kStateIdle); 95 backend_->Stop();
103 backend_->GetAudio()->SetState(AudioPipelineDevice::kStateIdle);
104 }
105 backend_.reset(); 96 backend_.reset();
106 } 97 }
107 98
108 void Start() { 99 void Start() {
109 DCHECK(thread_checker_.CalledOnValidThread()); 100 DCHECK(thread_checker_.CalledOnValidThread());
101 DCHECK(backend_);
110 102
111 MediaClockDevice* clock_device = backend_->GetClock(); 103 if (first_start_)
112 clock_device->SetState(MediaClockDevice::kStateRunning); 104 backend_->Start(0);
113 clock_device->SetRate(1.0f); 105 else
114 106 backend_->Resume();
115 AudioPipelineDevice* audio_device = backend_->GetAudio();
116 audio_device->SetState(AudioPipelineDevice::kStateRunning);
117 } 107 }
118 108
119 void Stop() { 109 void Stop() {
120 DCHECK(thread_checker_.CalledOnValidThread()); 110 DCHECK(thread_checker_.CalledOnValidThread());
111 DCHECK(backend_);
121 112
122 MediaClockDevice* clock_device = backend_->GetClock(); 113 backend_->Pause();
123 clock_device->SetRate(0.0f); 114 first_start_ = false;
124 } 115 }
125 116
126 void PushFrame(scoped_refptr<media::DecoderBufferBase> decoder_buffer, 117 void PushBuffer(scoped_refptr<media::DecoderBufferBase> decoder_buffer,
127 const PushFrameCompletionCallback& completion_cb) { 118 const PushBufferCompletionCallback& completion_cb) {
128 DCHECK(thread_checker_.CalledOnValidThread()); 119 DCHECK(thread_checker_.CalledOnValidThread());
120 DCHECK(decoder_);
121 DCHECK(completion_cb_.is_null());
122 if (error_) {
123 completion_cb.Run(false);
124 return;
125 }
129 126
130 AudioPipelineDevice* audio_device = backend_->GetAudio(); 127 if (backend_buffer_)
131 MediaComponentDevice::FrameStatus status = 128 backend_buffer_->set_buffer(decoder_buffer);
132 audio_device->PushFrame(nullptr, // decrypt_context 129 else
133 new CastDecoderBufferImpl(decoder_buffer), 130 backend_buffer_.reset(new CastDecoderBufferImpl(decoder_buffer));
134 new media::FrameStatusCBImpl(base::Bind(
135 &Backend::OnPushFrameStatus,
136 base::Unretained(this), completion_cb)));
137 131
138 if (status != MediaComponentDevice::kFramePending) 132 MediaPipelineBackend::BufferStatus status =
139 OnPushFrameStatus(completion_cb, status); 133 decoder_->PushBuffer(nullptr, backend_buffer_.get());
134 completion_cb_ = completion_cb;
135 if (status != MediaPipelineBackend::kBufferPending)
136 OnPushBufferComplete(decoder_, status);
140 } 137 }
141 138
142 void SetVolume(double volume) { 139 void SetVolume(double volume) {
143 DCHECK(thread_checker_.CalledOnValidThread()); 140 DCHECK(thread_checker_.CalledOnValidThread());
141 DCHECK(decoder_);
142 decoder_->SetVolume(volume);
143 }
144 144
145 AudioPipelineDevice* audio_device = backend_->GetAudio(); 145 // MediaPipelineBackend::Delegate implementation
146 audio_device->SetStreamVolumeMultiplier(volume); 146 void OnVideoResolutionChanged(MediaPipelineBackend::VideoDecoder* decoder,
147 const Size& size) override {}
148
149 void OnPushBufferComplete(
150 MediaPipelineBackend::Decoder* decoder,
151 MediaPipelineBackend::BufferStatus status) override {
152 DCHECK(thread_checker_.CalledOnValidThread());
153 DCHECK_NE(status, MediaPipelineBackend::kBufferPending);
154
155 base::ResetAndReturn(&completion_cb_)
156 .Run(status == MediaPipelineBackend::kBufferSuccess);
157 }
158
159 void OnEndOfStream(MediaPipelineBackend::Decoder* decoder) override {}
160
161 void OnDecoderError(MediaPipelineBackend::Decoder* decoder) override {
162 error_ = true;
163 if (!completion_cb_.is_null())
164 OnPushBufferComplete(decoder_, MediaPipelineBackend::kBufferFailed);
147 } 165 }
148 166
149 private: 167 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_; 168 const ::media::AudioParameters audio_params_;
159 scoped_ptr<MediaPipelineBackend> backend_; 169 scoped_ptr<MediaPipelineBackend> backend_;
170 MediaPipelineBackend::AudioDecoder* decoder_;
171 PushBufferCompletionCallback completion_cb_;
172 bool first_start_;
173 bool error_;
174 scoped_ptr<CastDecoderBufferImpl> backend_buffer_;
160 base::ThreadChecker thread_checker_; 175 base::ThreadChecker thread_checker_;
161 DISALLOW_COPY_AND_ASSIGN(Backend); 176 DISALLOW_COPY_AND_ASSIGN(Backend);
162 }; 177 };
163 178
164 // CastAudioOutputStream runs on audio thread (AudioManager::GetTaskRunner). 179 // CastAudioOutputStream runs on audio thread (AudioManager::GetTaskRunner).
165 CastAudioOutputStream::CastAudioOutputStream( 180 CastAudioOutputStream::CastAudioOutputStream(
166 const ::media::AudioParameters& audio_params, 181 const ::media::AudioParameters& audio_params,
167 CastAudioManager* audio_manager) 182 CastAudioManager* audio_manager)
168 : audio_params_(audio_params), 183 : audio_params_(audio_params),
169 audio_manager_(audio_manager), 184 audio_manager_(audio_manager),
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 248 DCHECK(audio_task_runner_->BelongsToCurrentThread());
234 DCHECK(source_callback); 249 DCHECK(source_callback);
235 250
236 source_callback_ = source_callback; 251 source_callback_ = source_callback;
237 backend_task_runner_->PostTask( 252 backend_task_runner_->PostTask(
238 FROM_HERE, base::Bind(&Backend::Start, base::Unretained(backend_.get()))); 253 FROM_HERE, base::Bind(&Backend::Start, base::Unretained(backend_.get())));
239 254
240 next_push_time_ = base::TimeTicks::Now(); 255 next_push_time_ = base::TimeTicks::Now();
241 if (!backend_busy_) { 256 if (!backend_busy_) {
242 audio_task_runner_->PostTask(FROM_HERE, 257 audio_task_runner_->PostTask(FROM_HERE,
243 base::Bind(&CastAudioOutputStream::PushFrame, 258 base::Bind(&CastAudioOutputStream::PushBuffer,
244 weak_factory_.GetWeakPtr())); 259 weak_factory_.GetWeakPtr()));
245 } 260 }
246 261
247 metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstAudio(); 262 metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstAudio();
248 } 263 }
249 264
250 void CastAudioOutputStream::Stop() { 265 void CastAudioOutputStream::Stop() {
251 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 266 DCHECK(audio_task_runner_->BelongsToCurrentThread());
252 267
253 source_callback_ = nullptr; 268 source_callback_ = nullptr;
(...skipping 18 matching lines...) Expand all
272 287
273 void CastAudioOutputStream::OnClosed() { 288 void CastAudioOutputStream::OnClosed() {
274 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 289 DCHECK(audio_task_runner_->BelongsToCurrentThread());
275 290
276 VLOG(1) << __FUNCTION__ << " : " << this; 291 VLOG(1) << __FUNCTION__ << " : " << this;
277 // Signal to the manager that we're closed and can be removed. 292 // 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". 293 // This should be the last call in the function as it deletes "this".
279 audio_manager_->ReleaseOutputStream(this); 294 audio_manager_->ReleaseOutputStream(this);
280 } 295 }
281 296
282 void CastAudioOutputStream::PushFrame() { 297 void CastAudioOutputStream::PushBuffer() {
283 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 298 DCHECK(audio_task_runner_->BelongsToCurrentThread());
284 DCHECK(!backend_busy_); 299 DCHECK(!backend_busy_);
285 300
286 if (!source_callback_) 301 if (!source_callback_)
287 return; 302 return;
288 303
289 uint32_t bytes_delay = 0; 304 uint32_t bytes_delay = 0;
290 int frame_count = source_callback_->OnMoreData(audio_bus_.get(), bytes_delay); 305 int frame_count = source_callback_->OnMoreData(audio_bus_.get(), bytes_delay);
291 VLOG(3) << "frames_filled=" << frame_count << " with latency=" << bytes_delay; 306 VLOG(3) << "frames_filled=" << frame_count << " with latency=" << bytes_delay;
292 307
293 DCHECK_EQ(frame_count, audio_bus_->frames()); 308 DCHECK_EQ(frame_count, audio_bus_->frames());
294 DCHECK_EQ(static_cast<int>(decoder_buffer_->data_size()), 309 DCHECK_EQ(static_cast<int>(decoder_buffer_->data_size()),
295 frame_count * audio_params_.GetBytesPerFrame()); 310 frame_count * audio_params_.GetBytesPerFrame());
296 audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8, 311 audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8,
297 decoder_buffer_->writable_data()); 312 decoder_buffer_->writable_data());
298 313
299 auto completion_cb = ::media::BindToCurrentLoop(base::Bind( 314 auto completion_cb = ::media::BindToCurrentLoop(
300 &CastAudioOutputStream::OnPushFrameComplete, weak_factory_.GetWeakPtr())); 315 base::Bind(&CastAudioOutputStream::OnPushBufferComplete,
301 backend_task_runner_->PostTask( 316 weak_factory_.GetWeakPtr()));
302 FROM_HERE, 317 backend_task_runner_->PostTask(FROM_HERE,
303 base::Bind(&Backend::PushFrame, base::Unretained(backend_.get()), 318 base::Bind(&Backend::PushBuffer,
304 decoder_buffer_, completion_cb)); 319 base::Unretained(backend_.get()),
320 decoder_buffer_,
321 completion_cb));
305 backend_busy_ = true; 322 backend_busy_ = true;
306 } 323 }
307 324
308 void CastAudioOutputStream::OnPushFrameComplete(bool success) { 325 void CastAudioOutputStream::OnPushBufferComplete(bool success) {
309 DCHECK(audio_task_runner_->BelongsToCurrentThread()); 326 DCHECK(audio_task_runner_->BelongsToCurrentThread());
310 327
311 backend_busy_ = false; 328 backend_busy_ = false;
312 if (!source_callback_) 329 if (!source_callback_)
313 return; 330 return;
314 331
315 if (!success) { 332 if (!success) {
316 source_callback_->OnError(this); 333 source_callback_->OnError(this);
317 return; 334 return;
318 } 335 }
319 336
320 // Schedule next push frame. 337 // Schedule next push buffer.
321 // Need to account for time spent in pulling and pushing frame as well 338 // Need to account for time spent in pulling and pushing buffer as well
322 // as the imprecision of PostDelayedTask(). 339 // as the imprecision of PostDelayedTask().
323 const base::TimeTicks now = base::TimeTicks::Now(); 340 const base::TimeTicks now = base::TimeTicks::Now();
324 base::TimeDelta delay = next_push_time_ + buffer_duration_ - now; 341 base::TimeDelta delay = next_push_time_ + buffer_duration_ - now;
325 delay = std::max(delay, base::TimeDelta()); 342 delay = std::max(delay, base::TimeDelta());
326 next_push_time_ = now + delay; 343 next_push_time_ = now + delay;
327 344
328 audio_task_runner_->PostDelayedTask( 345 audio_task_runner_->PostDelayedTask(
329 FROM_HERE, 346 FROM_HERE,
330 base::Bind(&CastAudioOutputStream::PushFrame, weak_factory_.GetWeakPtr()), 347 base::Bind(&CastAudioOutputStream::PushBuffer,
348 weak_factory_.GetWeakPtr()),
331 delay); 349 delay);
332 } 350 }
333 351
334 } // namespace media 352 } // namespace media
335 } // namespace chromecast 353 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698