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

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

Issue 2879703003: [chromecast] Moves CastAudioOutputStream::Backend to CMA thread. (Closed)
Patch Set: addressed comments Created 3 years, 6 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 <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/threading/thread_task_runner_handle.h"
12 #include "chromecast/base/metrics/cast_metrics_helper.h" 14 #include "chromecast/base/metrics/cast_metrics_helper.h"
13 #include "chromecast/base/task_runner_impl.h" 15 #include "chromecast/base/task_runner_impl.h"
14 #include "chromecast/media/audio/cast_audio_manager.h" 16 #include "chromecast/media/audio/cast_audio_manager.h"
17 #include "chromecast/media/cma/backend/media_pipeline_backend_factory.h"
15 #include "chromecast/media/cma/base/decoder_buffer_adapter.h" 18 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
16 #include "chromecast/public/media/decoder_config.h" 19 #include "chromecast/public/media/decoder_config.h"
17 #include "chromecast/public/media/media_pipeline_backend.h" 20 #include "chromecast/public/media/media_pipeline_backend.h"
18 #include "chromecast/public/media/media_pipeline_device_params.h" 21 #include "chromecast/public/media/media_pipeline_device_params.h"
19 #include "chromecast/public/volume_control.h" 22 #include "chromecast/public/volume_control.h"
20 #include "media/audio/audio_device_description.h" 23 #include "media/audio/audio_device_description.h"
24 #include "media/base/audio_timestamp_helper.h"
21 #include "media/base/decoder_buffer.h" 25 #include "media/base/decoder_buffer.h"
22 26
23 namespace { 27 namespace {
24 const int kMaxQueuedDataMs = 1000; 28 const int kMaxQueuedDataMs = 1000;
29
30 void SignalWaitableEvent(bool* success,
31 base::WaitableEvent* waitable_event,
32 bool result) {
33 *success = result;
34 waitable_event->Signal();
35 }
25 } // namespace 36 } // namespace
26 37
27 namespace chromecast { 38 namespace chromecast {
28 namespace media { 39 namespace media {
29 40
30 // Backend represents a MediaPipelineBackend adapter. 41 // Backend represents a MediaPipelineBackend adapter.
31 // It can be created and destroyed on any thread, 42 // It can be created and destroyed on any thread,
32 // but all other member functions must be called on a single thread. 43 // but all other member functions must be called on a single thread.
33 class CastAudioOutputStream::Backend 44 class CastAudioOutputStream::Backend
34 : public MediaPipelineBackend::Decoder::Delegate { 45 : public MediaPipelineBackend::Decoder::Delegate {
35 public: 46 public:
36 using PushBufferCompletionCallback = base::Callback<void(bool)>; 47 using OpenCompletionCallback = base::OnceCallback<void(bool)>;
37 48
38 Backend() : decoder_(nullptr), first_start_(true), error_(false) { 49 Backend(const ::media::AudioParameters& audio_params)
39 thread_checker_.DetachFromThread(); 50 : audio_params_(audio_params),
51 timestamp_helper_(audio_params_.sample_rate()),
52 buffer_duration_(audio_params.GetBufferDuration()),
53 first_start_(true),
54 push_in_progress_(false),
55 decoder_(nullptr),
56 source_callback_(nullptr),
57 weak_factory_(this) {
58 DETACH_FROM_THREAD(thread_checker_);
40 } 59 }
41 ~Backend() override {} 60 ~Backend() override {
61 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
62 if (backend_ && !first_start_) // Only stop the backend if it was started.
63 backend_->Stop();
64 }
42 65
43 bool Open(const ::media::AudioParameters& audio_params, 66 void Open(MediaPipelineBackendFactory* backend_factory,
44 CastAudioManager* audio_manager) { 67 OpenCompletionCallback completion_cb) {
45 DCHECK(thread_checker_.CalledOnValidThread()); 68 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
46 DCHECK(audio_manager); 69 DCHECK(backend_factory);
47 DCHECK(backend_ == nullptr); 70 DCHECK(backend_ == nullptr);
48 71
49 backend_task_runner_.reset(new TaskRunnerImpl()); 72 backend_task_runner_.reset(new TaskRunnerImpl());
50 MediaPipelineDeviceParams device_params( 73 MediaPipelineDeviceParams device_params(
51 MediaPipelineDeviceParams::kModeIgnorePts, 74 MediaPipelineDeviceParams::kModeIgnorePts,
52 MediaPipelineDeviceParams::kAudioStreamSoundEffects, 75 MediaPipelineDeviceParams::kAudioStreamSoundEffects,
53 backend_task_runner_.get(), AudioContentType::kMedia, 76 backend_task_runner_.get(), AudioContentType::kMedia,
54 ::media::AudioDeviceDescription::kDefaultDeviceId); 77 ::media::AudioDeviceDescription::kDefaultDeviceId);
55 backend_ = audio_manager->CreateMediaPipelineBackend(device_params); 78 backend_ = backend_factory->CreateBackend(device_params);
56 if (!backend_) 79 if (!backend_) {
57 return false; 80 std::move(completion_cb).Run(false);
81 return;
82 }
58 83
59 decoder_ = backend_->CreateAudioDecoder(); 84 decoder_ = backend_->CreateAudioDecoder();
60 if (!decoder_) 85 if (!decoder_) {
61 return false; 86 std::move(completion_cb).Run(false);
87 return;
88 }
62 decoder_->SetDelegate(this); 89 decoder_->SetDelegate(this);
63 90
64 AudioConfig audio_config; 91 AudioConfig audio_config;
65 audio_config.codec = kCodecPCM; 92 audio_config.codec = kCodecPCM;
66 audio_config.sample_format = kSampleFormatS16; 93 audio_config.sample_format = kSampleFormatS16;
67 audio_config.bytes_per_channel = audio_params.bits_per_sample() / 8; 94 audio_config.bytes_per_channel = audio_params_.bits_per_sample() / 8;
68 audio_config.channel_number = audio_params.channels(); 95 audio_config.channel_number = audio_params_.channels();
69 audio_config.samples_per_second = audio_params.sample_rate(); 96 audio_config.samples_per_second = audio_params_.sample_rate();
70 if (!decoder_->SetConfig(audio_config)) 97 if (!decoder_->SetConfig(audio_config)) {
71 return false; 98 std::move(completion_cb).Run(false);
99 return;
100 }
72 101
73 return backend_->Initialize(); 102 if (!backend_->Initialize()) {
103 std::move(completion_cb).Run(false);
104 return;
105 }
106
107 audio_bus_ = ::media::AudioBus::Create(audio_params_);
108 decoder_buffer_ = new DecoderBufferAdapter(
109 new ::media::DecoderBuffer(audio_params_.GetBytesPerBuffer()));
110 timestamp_helper_.SetBaseTimestamp(base::TimeDelta());
111 std::move(completion_cb).Run(true);
74 } 112 }
75 113
76 void Close() { 114 void Start(AudioSourceCallback* source_callback) {
77 DCHECK(thread_checker_.CalledOnValidThread()); 115 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
78
79 if (backend_ && !first_start_) // Only stop the backend if it was started.
80 backend_->Stop();
81 backend_.reset();
82 backend_task_runner_.reset();
83 }
84
85 void Start() {
86 DCHECK(thread_checker_.CalledOnValidThread());
87 DCHECK(backend_); 116 DCHECK(backend_);
88 117
89 if (first_start_) { 118 if (first_start_) {
90 first_start_ = false; 119 first_start_ = false;
91 backend_->Start(0); 120 backend_->Start(0);
92 } else { 121 } else {
93 backend_->Resume(); 122 backend_->Resume();
94 } 123 }
124
125 source_callback_ = source_callback;
126 next_push_time_ = base::TimeTicks::Now();
127 if (!push_in_progress_) {
128 push_in_progress_ = true;
129 PushBuffer();
130 }
95 } 131 }
96 132
97 void Stop() { 133 void Stop(base::OnceClosure completion_cb) {
98 DCHECK(thread_checker_.CalledOnValidThread()); 134 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
99 DCHECK(backend_); 135 DCHECK(backend_);
100 136
101 backend_->Pause(); 137 backend_->Pause();
138 source_callback_ = nullptr;
139 std::move(completion_cb).Run();
102 } 140 }
103 141
104 void PushBuffer(scoped_refptr<media::DecoderBufferBase> decoder_buffer, 142 void SetVolume(double volume) {
105 const PushBufferCompletionCallback& completion_cb) { 143 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
106 DCHECK(thread_checker_.CalledOnValidThread());
107 DCHECK(decoder_); 144 DCHECK(decoder_);
108 DCHECK(!completion_cb.is_null()); 145 decoder_->SetVolume(volume);
109 DCHECK(completion_cb_.is_null()); 146 }
110 if (error_) { 147
111 completion_cb.Run(false); 148 private:
149 void PushBuffer() {
150 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
151 DCHECK(push_in_progress_);
152
153 if (!source_callback_) {
154 push_in_progress_ = false;
112 return; 155 return;
113 } 156 }
114 157
115 backend_buffer_ = decoder_buffer; 158 MediaPipelineBackend::AudioDecoder::RenderingDelay rendering_delay =
116 completion_cb_ = completion_cb; 159 decoder_->GetRenderingDelay();
117 BufferStatus status = decoder_->PushBuffer(backend_buffer_.get()); 160 base::TimeDelta delay =
161 base::TimeDelta::FromMicroseconds(rendering_delay.delay_microseconds);
162 base::TimeTicks delay_timestamp =
163 base::TimeTicks() + base::TimeDelta::FromMicroseconds(
164 rendering_delay.timestamp_microseconds);
165 int frame_count = source_callback_->OnMoreData(delay, delay_timestamp, 0,
166 audio_bus_.get());
167 VLOG(3) << "frames_filled=" << frame_count << " with latency=" << delay;
168
169 DCHECK_EQ(frame_count, audio_bus_->frames());
170 DCHECK_EQ(static_cast<int>(decoder_buffer_->data_size()),
171 frame_count * audio_params_.GetBytesPerFrame());
172 audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8,
173 decoder_buffer_->writable_data());
174 decoder_buffer_->set_timestamp(timestamp_helper_.GetTimestamp());
175 timestamp_helper_.AddFrames(frame_count);
176
177 BufferStatus status = decoder_->PushBuffer(decoder_buffer_.get());
118 if (status != MediaPipelineBackend::kBufferPending) 178 if (status != MediaPipelineBackend::kBufferPending)
119 OnPushBufferComplete(status); 179 OnPushBufferComplete(status);
120 } 180 }
121 181
122 void SetVolume(double volume) {
123 DCHECK(thread_checker_.CalledOnValidThread());
124 DCHECK(decoder_);
125 decoder_->SetVolume(volume);
126 }
127
128 MediaPipelineBackend::AudioDecoder::RenderingDelay GetRenderingDelay() {
129 DCHECK(thread_checker_.CalledOnValidThread());
130 DCHECK(decoder_);
131 return decoder_->GetRenderingDelay();
132 }
133
134 private:
135 // MediaPipelineBackend::Decoder::Delegate implementation 182 // MediaPipelineBackend::Decoder::Delegate implementation
136 void OnPushBufferComplete(BufferStatus status) override { 183 void OnPushBufferComplete(BufferStatus status) override {
137 DCHECK(thread_checker_.CalledOnValidThread()); 184 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
138 DCHECK_NE(status, MediaPipelineBackend::kBufferPending); 185 DCHECK_NE(status, MediaPipelineBackend::kBufferPending);
139 186
140 // |completion_cb_| may be null if OnDecoderError was called. 187 DCHECK(push_in_progress_);
141 if (completion_cb_.is_null()) 188 push_in_progress_ = false;
189
190 if (!source_callback_)
142 return; 191 return;
143 192
144 base::ResetAndReturn(&completion_cb_) 193 if (status != MediaPipelineBackend::kBufferSuccess) {
145 .Run(status == MediaPipelineBackend::kBufferSuccess); 194 source_callback_->OnError();
195 return;
196 }
197
198 // Schedule next push buffer. We don't want to allow more than
199 // kMaxQueuedDataMs of queued audio.
200 const base::TimeTicks now = base::TimeTicks::Now();
201 next_push_time_ = std::max(now, next_push_time_ + buffer_duration_);
202
203 base::TimeDelta delay = (next_push_time_ - now) -
204 base::TimeDelta::FromMilliseconds(kMaxQueuedDataMs);
205 delay = std::max(delay, base::TimeDelta());
206
207 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
208 FROM_HERE, base::Bind(&Backend::PushBuffer, weak_factory_.GetWeakPtr()),
209 delay);
210 push_in_progress_ = true;
146 } 211 }
147 212
148 void OnEndOfStream() override {} 213 void OnEndOfStream() override {}
149 214
150 void OnDecoderError() override { 215 void OnDecoderError() override {
151 DCHECK(thread_checker_.CalledOnValidThread()); 216 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
152 error_ = true; 217 OnPushBufferComplete(MediaPipelineBackend::kBufferFailed);
153 if (!completion_cb_.is_null())
154 OnPushBufferComplete(MediaPipelineBackend::kBufferFailed);
155 } 218 }
156 219
157 void OnKeyStatusChanged(const std::string& key_id, 220 void OnKeyStatusChanged(const std::string& key_id,
158 CastKeyStatus key_status, 221 CastKeyStatus key_status,
159 uint32_t system_code) override {} 222 uint32_t system_code) override {}
160 223
161 void OnVideoResolutionChanged(const Size& size) override {} 224 void OnVideoResolutionChanged(const Size& size) override {}
162 225
226 const ::media::AudioParameters audio_params_;
227 std::unique_ptr<::media::AudioBus> audio_bus_;
228 scoped_refptr<media::DecoderBufferBase> decoder_buffer_;
229 ::media::AudioTimestampHelper timestamp_helper_;
230 const base::TimeDelta buffer_duration_;
231 bool first_start_;
232 bool push_in_progress_;
233 base::TimeTicks next_push_time_;
234 std::unique_ptr<TaskRunnerImpl> backend_task_runner_;
163 std::unique_ptr<MediaPipelineBackend> backend_; 235 std::unique_ptr<MediaPipelineBackend> backend_;
164 std::unique_ptr<TaskRunnerImpl> backend_task_runner_;
165 MediaPipelineBackend::AudioDecoder* decoder_; 236 MediaPipelineBackend::AudioDecoder* decoder_;
166 PushBufferCompletionCallback completion_cb_; 237 AudioSourceCallback* source_callback_;
167 bool first_start_;
168 bool error_;
169 scoped_refptr<DecoderBufferBase> backend_buffer_;
170 base::ThreadChecker thread_checker_;
171 238
239 THREAD_CHECKER(thread_checker_);
240 base::WeakPtrFactory<Backend> weak_factory_;
172 DISALLOW_COPY_AND_ASSIGN(Backend); 241 DISALLOW_COPY_AND_ASSIGN(Backend);
173 }; 242 };
174 243
175 // CastAudioOutputStream runs on audio thread (AudioManager::GetTaskRunner). 244 // CastAudioOutputStream runs on audio thread (AudioManager::GetTaskRunner).
176 CastAudioOutputStream::CastAudioOutputStream( 245 CastAudioOutputStream::CastAudioOutputStream(
177 const ::media::AudioParameters& audio_params, 246 const ::media::AudioParameters& audio_params,
178 CastAudioManager* audio_manager) 247 CastAudioManager* audio_manager)
179 : audio_params_(audio_params), 248 : audio_params_(audio_params), audio_manager_(audio_manager), volume_(1.0) {
180 audio_manager_(audio_manager),
181 volume_(1.0),
182 source_callback_(nullptr),
183 timestamp_helper_(audio_params_.sample_rate()),
184 backend_(new Backend()),
185 buffer_duration_(audio_params.GetBufferDuration()),
186 push_in_progress_(false),
187 weak_factory_(this) {
188 VLOG(1) << "CastAudioOutputStream " << this << " created with " 249 VLOG(1) << "CastAudioOutputStream " << this << " created with "
189 << audio_params_.AsHumanReadableString(); 250 << audio_params_.AsHumanReadableString();
190 } 251 }
191 252
192 CastAudioOutputStream::~CastAudioOutputStream() { 253 CastAudioOutputStream::~CastAudioOutputStream() {
254 DCHECK(!backend_);
193 } 255 }
194 256
195 bool CastAudioOutputStream::Open() { 257 bool CastAudioOutputStream::Open() {
258 VLOG(1) << this << ": " << __func__;
196 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 259 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
197 260
198 ::media::AudioParameters::Format format = audio_params_.format(); 261 ::media::AudioParameters::Format format = audio_params_.format();
199 DCHECK((format == ::media::AudioParameters::AUDIO_PCM_LINEAR) || 262 DCHECK((format == ::media::AudioParameters::AUDIO_PCM_LINEAR) ||
200 (format == ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY)); 263 (format == ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY));
201 264
202 ::media::ChannelLayout channel_layout = audio_params_.channel_layout(); 265 ::media::ChannelLayout channel_layout = audio_params_.channel_layout();
203 if ((channel_layout != ::media::CHANNEL_LAYOUT_MONO) && 266 if ((channel_layout != ::media::CHANNEL_LAYOUT_MONO) &&
204 (channel_layout != ::media::CHANNEL_LAYOUT_STEREO)) { 267 (channel_layout != ::media::CHANNEL_LAYOUT_STEREO)) {
205 LOG(WARNING) << "Unsupported channel layout: " << channel_layout; 268 LOG(WARNING) << "Unsupported channel layout: " << channel_layout;
206 return false; 269 return false;
207 } 270 }
208 DCHECK_GE(audio_params_.channels(), 1); 271 DCHECK_GE(audio_params_.channels(), 1);
209 DCHECK_LE(audio_params_.channels(), 2); 272 DCHECK_LE(audio_params_.channels(), 2);
210 273
211 if (!backend_->Open(audio_params_, audio_manager_)) { 274 bool success = false;
212 LOG(WARNING) << "Failed to create media pipeline backend."; 275 DCHECK(!backend_);
213 return false; 276 backend_ = base::MakeUnique<Backend>(audio_params_);
277 {
278 base::WaitableEvent completion_event(
279 base::WaitableEvent::ResetPolicy::AUTOMATIC,
280 base::WaitableEvent::InitialState::NOT_SIGNALED);
281 audio_manager_->backend_task_runner()->PostTask(
282 FROM_HERE,
283 base::BindOnce(
284 &Backend::Open, base::Unretained(backend_.get()),
285 audio_manager_->backend_factory(),
286 base::BindOnce(&SignalWaitableEvent, &success, &completion_event)));
287 completion_event.Wait();
214 } 288 }
215 289
216 audio_bus_ = ::media::AudioBus::Create(audio_params_); 290 if (!success)
217 decoder_buffer_ = new DecoderBufferAdapter( 291 LOG(WARNING) << "Failed to open audio output stream.";
218 new ::media::DecoderBuffer(audio_params_.GetBytesPerBuffer())); 292 return success;
219 timestamp_helper_.SetBaseTimestamp(base::TimeDelta());
220
221 VLOG(1) << __FUNCTION__ << " : " << this;
222 return true;
223 } 293 }
224 294
225 void CastAudioOutputStream::Close() { 295 void CastAudioOutputStream::Close() {
296 VLOG(1) << this << ": " << __func__;
226 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 297 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
227 VLOG(1) << __FUNCTION__ << " : " << this;
228 298
229 backend_->Close(); 299 DCHECK(backend_);
300 audio_manager_->backend_task_runner()->DeleteSoon(FROM_HERE,
301 backend_.release());
302
230 // Signal to the manager that we're closed and can be removed. 303 // Signal to the manager that we're closed and can be removed.
231 // This should be the last call in the function as it deletes "this". 304 // This should be the last call in the function as it deletes "this".
232 audio_manager_->ReleaseOutputStream(this); 305 audio_manager_->ReleaseOutputStream(this);
233 } 306 }
234 307
235 void CastAudioOutputStream::Start(AudioSourceCallback* source_callback) { 308 void CastAudioOutputStream::Start(AudioSourceCallback* source_callback) {
309 VLOG(2) << this << ": " << __func__;
236 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 310 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
237 DCHECK(source_callback); 311 DCHECK(source_callback);
312 DCHECK(backend_);
238 313
239 source_callback_ = source_callback; 314 audio_manager_->backend_task_runner()->PostTask(
240 backend_->Start(); 315 FROM_HERE,
241 316 base::BindOnce(&Backend::Start, base::Unretained(backend_.get()),
242 next_push_time_ = base::TimeTicks::Now(); 317 source_callback));
243 if (!push_in_progress_) {
244 audio_manager_->GetTaskRunner()->PostTask(
245 FROM_HERE, base::Bind(&CastAudioOutputStream::PushBuffer,
246 weak_factory_.GetWeakPtr()));
247 push_in_progress_ = true;
248 }
249 318
250 metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstAudio(); 319 metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstAudio();
251 } 320 }
252 321
253 void CastAudioOutputStream::Stop() { 322 void CastAudioOutputStream::Stop() {
323 VLOG(2) << this << ": " << __func__;
254 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 324 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
325 DCHECK(backend_);
255 326
256 source_callback_ = nullptr; 327 base::WaitableEvent completion_event(
257 backend_->Stop(); 328 base::WaitableEvent::ResetPolicy::AUTOMATIC,
329 base::WaitableEvent::InitialState::NOT_SIGNALED);
330 audio_manager_->backend_task_runner()->PostTask(
331 FROM_HERE,
332 base::BindOnce(&Backend::Stop, base::Unretained(backend_.get()),
333 base::BindOnce(&base::WaitableEvent::Signal,
334 base::Unretained(&completion_event))));
335 completion_event.Wait();
258 } 336 }
259 337
260 void CastAudioOutputStream::SetVolume(double volume) { 338 void CastAudioOutputStream::SetVolume(double volume) {
339 VLOG(2) << this << ": " << __func__ << "(" << volume << ")";
261 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 340 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
262 341
263 volume_ = volume; 342 volume_ = volume;
264 backend_->SetVolume(volume); 343 if (backend_) {
344 audio_manager_->backend_task_runner()->PostTask(
345 FROM_HERE, base::BindOnce(&Backend::SetVolume,
346 base::Unretained(backend_.get()), volume_));
347 }
265 } 348 }
266 349
267 void CastAudioOutputStream::GetVolume(double* volume) { 350 void CastAudioOutputStream::GetVolume(double* volume) {
268 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 351 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
269 352
270 *volume = volume_; 353 *volume = volume_;
271 } 354 }
272 355
273 void CastAudioOutputStream::PushBuffer() {
274 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
275 DCHECK(push_in_progress_);
276
277 if (!source_callback_) {
278 push_in_progress_ = false;
279 return;
280 }
281
282 MediaPipelineBackend::AudioDecoder::RenderingDelay rendering_delay =
283 backend_->GetRenderingDelay();
284 base::TimeDelta delay =
285 base::TimeDelta::FromMicroseconds(rendering_delay.delay_microseconds);
286 base::TimeTicks delay_timestamp =
287 base::TimeTicks() +
288 base::TimeDelta::FromMicroseconds(rendering_delay.timestamp_microseconds);
289 int frame_count =
290 source_callback_->OnMoreData(delay, delay_timestamp, 0, audio_bus_.get());
291 VLOG(3) << "frames_filled=" << frame_count << " with latency=" << delay;
292
293 DCHECK_EQ(frame_count, audio_bus_->frames());
294 DCHECK_EQ(static_cast<int>(decoder_buffer_->data_size()),
295 frame_count * audio_params_.GetBytesPerFrame());
296 audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8,
297 decoder_buffer_->writable_data());
298 decoder_buffer_->set_timestamp(timestamp_helper_.GetTimestamp());
299 timestamp_helper_.AddFrames(frame_count);
300
301 auto completion_cb = base::Bind(&CastAudioOutputStream::OnPushBufferComplete,
302 weak_factory_.GetWeakPtr());
303 backend_->PushBuffer(decoder_buffer_, completion_cb);
304 }
305
306 void CastAudioOutputStream::OnPushBufferComplete(bool success) {
307 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
308 DCHECK(push_in_progress_);
309
310 push_in_progress_ = false;
311
312 if (!source_callback_)
313 return;
314 if (!success) {
315 source_callback_->OnError();
316 return;
317 }
318
319 // Schedule next push buffer. We don't want to allow more than
320 // kMaxQueuedDataMs of queued audio.
321 const base::TimeTicks now = base::TimeTicks::Now();
322 next_push_time_ = std::max(now, next_push_time_ + buffer_duration_);
323
324 base::TimeDelta delay = (next_push_time_ - now) -
325 base::TimeDelta::FromMilliseconds(kMaxQueuedDataMs);
326 delay = std::max(delay, base::TimeDelta());
327
328 audio_manager_->GetTaskRunner()->PostDelayedTask(
329 FROM_HERE, base::Bind(&CastAudioOutputStream::PushBuffer,
330 weak_factory_.GetWeakPtr()),
331 delay);
332 push_in_progress_ = true;
333 }
334
335 } // namespace media 356 } // namespace media
336 } // namespace chromecast 357 } // namespace chromecast
OLDNEW
« no previous file with comments | « chromecast/media/audio/cast_audio_output_stream.h ('k') | chromecast/media/audio/cast_audio_output_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698