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