| 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 |