OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/renderer/media/webrtc_audio_renderer.h" | 5 #include "content/renderer/media/webrtc_audio_renderer.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 const std::string& device_id, | 160 const std::string& device_id, |
161 const url::Origin& security_origin) | 161 const url::Origin& security_origin) |
162 : state_(UNINITIALIZED), | 162 : state_(UNINITIALIZED), |
163 source_render_frame_id_(source_render_frame_id), | 163 source_render_frame_id_(source_render_frame_id), |
164 session_id_(session_id), | 164 session_id_(session_id), |
165 signaling_thread_(signaling_thread), | 165 signaling_thread_(signaling_thread), |
166 media_stream_(media_stream), | 166 media_stream_(media_stream), |
167 source_(NULL), | 167 source_(NULL), |
168 play_ref_count_(0), | 168 play_ref_count_(0), |
169 start_ref_count_(0), | 169 start_ref_count_(0), |
170 audio_delay_milliseconds_(0), | |
171 sink_params_(kFormat, kChannelLayout, 0, kBitsPerSample, 0), | 170 sink_params_(kFormat, kChannelLayout, 0, kBitsPerSample, 0), |
172 output_device_id_(device_id), | 171 output_device_id_(device_id), |
173 security_origin_(security_origin) { | 172 security_origin_(security_origin) { |
174 WebRtcLogMessage(base::StringPrintf( | 173 WebRtcLogMessage(base::StringPrintf( |
175 "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i", | 174 "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i", |
176 source_render_frame_id, session_id, sink_params_.effects())); | 175 source_render_frame_id, session_id, sink_params_.effects())); |
177 } | 176 } |
178 | 177 |
179 WebRtcAudioRenderer::~WebRtcAudioRenderer() { | 178 WebRtcAudioRenderer::~WebRtcAudioRenderer() { |
180 DCHECK(thread_checker_.CalledOnValidThread()); | 179 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 if (state_ == UNINITIALIZED) | 260 if (state_ == UNINITIALIZED) |
262 return; | 261 return; |
263 | 262 |
264 DCHECK(play_ref_count_ == 0 || state_ == PLAYING); | 263 DCHECK(play_ref_count_ == 0 || state_ == PLAYING); |
265 ++play_ref_count_; | 264 ++play_ref_count_; |
266 | 265 |
267 if (state_ != PLAYING) { | 266 if (state_ != PLAYING) { |
268 state_ = PLAYING; | 267 state_ = PLAYING; |
269 | 268 |
270 if (audio_fifo_) { | 269 if (audio_fifo_) { |
271 audio_delay_milliseconds_ = 0; | 270 audio_delay_ = base::TimeDelta(); |
272 audio_fifo_->Clear(); | 271 audio_fifo_->Clear(); |
273 } | 272 } |
274 } | 273 } |
275 } | 274 } |
276 | 275 |
277 void WebRtcAudioRenderer::Pause() { | 276 void WebRtcAudioRenderer::Pause() { |
278 DVLOG(1) << "WebRtcAudioRenderer::Pause()"; | 277 DVLOG(1) << "WebRtcAudioRenderer::Pause()"; |
279 DCHECK(thread_checker_.CalledOnValidThread()); | 278 DCHECK(thread_checker_.CalledOnValidThread()); |
280 if (!playing_state_.playing()) | 279 if (!playing_state_.playing()) |
281 return; | 280 return; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 base::AutoLock auto_lock(lock_); | 393 base::AutoLock auto_lock(lock_); |
395 source_->AudioRendererThreadStopped(); | 394 source_->AudioRendererThreadStopped(); |
396 } | 395 } |
397 PrepareSink(); | 396 PrepareSink(); |
398 sink_->Start(); | 397 sink_->Start(); |
399 sink_->Play(); // Not all the sinks play on start. | 398 sink_->Play(); // Not all the sinks play on start. |
400 | 399 |
401 callback.Run(media::OUTPUT_DEVICE_STATUS_OK); | 400 callback.Run(media::OUTPUT_DEVICE_STATUS_OK); |
402 } | 401 } |
403 | 402 |
404 int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus, | 403 int WebRtcAudioRenderer::Render(base::TimeDelta delay, |
405 uint32_t frames_delayed, | 404 base::TimeTicks delay_timestamp, |
406 uint32_t frames_skipped) { | 405 int prior_frames_skipped, |
| 406 media::AudioBus* audio_bus) { |
407 DCHECK(sink_->CurrentThreadIsRenderingThread()); | 407 DCHECK(sink_->CurrentThreadIsRenderingThread()); |
408 base::AutoLock auto_lock(lock_); | 408 base::AutoLock auto_lock(lock_); |
409 if (!source_) | 409 if (!source_) |
410 return 0; | 410 return 0; |
411 | 411 |
412 // TODO(grunell): Converting from frames to milliseconds will potentially lose | 412 DVLOG(2) << "WebRtcAudioRenderer::Render()"; |
413 // hundreds of microseconds which may cause audio video drift. Update | 413 DVLOG(2) << "audio_delay: " << delay; |
414 // this class and all usage of render delay msec -> frames (possibly even | |
415 // using a double type for frames). See http://crbug.com/586540 | |
416 uint32_t audio_delay_milliseconds = static_cast<double>(frames_delayed) * | |
417 base::Time::kMillisecondsPerSecond / | |
418 sink_params_.sample_rate(); | |
419 | 414 |
420 DVLOG(2) << "WebRtcAudioRenderer::Render()"; | 415 audio_delay_ = delay; |
421 DVLOG(2) << "audio_delay_milliseconds: " << audio_delay_milliseconds; | |
422 | |
423 DCHECK_LE(audio_delay_milliseconds, static_cast<uint32_t>(INT_MAX)); | |
424 audio_delay_milliseconds_ = static_cast<int>(audio_delay_milliseconds); | |
425 | 416 |
426 // If there are skipped frames, pull and throw away the same amount. We always | 417 // If there are skipped frames, pull and throw away the same amount. We always |
427 // pull 10 ms of data from the source (see PrepareSink()), so the fifo is only | 418 // pull 10 ms of data from the source (see PrepareSink()), so the fifo is only |
428 // required if the number of frames to drop doesn't correspond to 10 ms. | 419 // required if the number of frames to drop doesn't correspond to 10 ms. |
429 if (frames_skipped > 0) { | 420 if (prior_frames_skipped > 0) { |
430 const uint32_t source_frames_per_buffer = | 421 const int source_frames_per_buffer = sink_params_.sample_rate() / 100; |
431 static_cast<uint32_t>(sink_params_.sample_rate() / 100); | 422 if (!audio_fifo_ && prior_frames_skipped != source_frames_per_buffer) { |
432 if (!audio_fifo_ && frames_skipped != source_frames_per_buffer) { | |
433 audio_fifo_.reset(new media::AudioPullFifo( | 423 audio_fifo_.reset(new media::AudioPullFifo( |
434 kChannels, source_frames_per_buffer, | 424 kChannels, source_frames_per_buffer, |
435 base::Bind(&WebRtcAudioRenderer::SourceCallback, | 425 base::Bind(&WebRtcAudioRenderer::SourceCallback, |
436 base::Unretained(this)))); | 426 base::Unretained(this)))); |
437 } | 427 } |
438 | 428 |
439 std::unique_ptr<media::AudioBus> drop_bus = | 429 std::unique_ptr<media::AudioBus> drop_bus = |
440 media::AudioBus::Create(audio_bus->channels(), frames_skipped); | 430 media::AudioBus::Create(audio_bus->channels(), prior_frames_skipped); |
441 if (audio_fifo_) | 431 if (audio_fifo_) |
442 audio_fifo_->Consume(drop_bus.get(), drop_bus->frames()); | 432 audio_fifo_->Consume(drop_bus.get(), drop_bus->frames()); |
443 else | 433 else |
444 SourceCallback(0, drop_bus.get()); | 434 SourceCallback(0, drop_bus.get()); |
445 } | 435 } |
446 | 436 |
447 // Pull the data we will deliver. | 437 // Pull the data we will deliver. |
448 if (audio_fifo_) | 438 if (audio_fifo_) |
449 audio_fifo_->Consume(audio_bus, audio_bus->frames()); | 439 audio_fifo_->Consume(audio_bus, audio_bus->frames()); |
450 else | 440 else |
451 SourceCallback(0, audio_bus); | 441 SourceCallback(0, audio_bus); |
452 | 442 |
453 return (state_ == PLAYING) ? audio_bus->frames() : 0; | 443 return (state_ == PLAYING) ? audio_bus->frames() : 0; |
454 } | 444 } |
455 | 445 |
456 void WebRtcAudioRenderer::OnRenderError() { | 446 void WebRtcAudioRenderer::OnRenderError() { |
457 NOTIMPLEMENTED(); | 447 NOTIMPLEMENTED(); |
458 LOG(ERROR) << "OnRenderError()"; | 448 LOG(ERROR) << "OnRenderError()"; |
459 } | 449 } |
460 | 450 |
461 // Called by AudioPullFifo when more data is necessary. | 451 // Called by AudioPullFifo when more data is necessary. |
462 void WebRtcAudioRenderer::SourceCallback( | 452 void WebRtcAudioRenderer::SourceCallback( |
463 int fifo_frame_delay, media::AudioBus* audio_bus) { | 453 int fifo_frame_delay, media::AudioBus* audio_bus) { |
464 DCHECK(sink_->CurrentThreadIsRenderingThread()); | 454 DCHECK(sink_->CurrentThreadIsRenderingThread()); |
465 base::TimeTicks start_time = base::TimeTicks::Now(); | 455 base::TimeTicks start_time = base::TimeTicks::Now(); |
466 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" | 456 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" |
467 << fifo_frame_delay << ", " | 457 << fifo_frame_delay << ", " |
468 << audio_bus->frames() << ")"; | 458 << audio_bus->frames() << ")"; |
469 | 459 |
470 int output_delay_milliseconds = audio_delay_milliseconds_; | 460 int output_delay_milliseconds = audio_delay_.InMilliseconds(); |
471 // TODO(grunell): This integer division by sample_rate will cause loss of | 461 // TODO(grunell): This integer division by sample_rate will cause loss of |
472 // partial milliseconds, and may cause avsync drift. http://crbug.com/586540 | 462 // partial milliseconds, and may cause avsync drift. http://crbug.com/586540 |
473 output_delay_milliseconds += fifo_frame_delay * | 463 output_delay_milliseconds += fifo_frame_delay * |
474 base::Time::kMillisecondsPerSecond / | 464 base::Time::kMillisecondsPerSecond / |
475 sink_params_.sample_rate(); | 465 sink_params_.sample_rate(); |
476 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; | 466 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; |
477 | 467 |
478 // We need to keep render data for the |source_| regardless of |state_|, | 468 // We need to keep render data for the |source_| regardless of |state_|, |
479 // otherwise the data will be buffered up inside |source_|. | 469 // otherwise the data will be buffered up inside |source_|. |
480 source_->RenderData(audio_bus, sink_params_.sample_rate(), | 470 source_->RenderData(audio_bus, sink_params_.sample_rate(), |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
668 sink_params_ = new_sink_params; | 658 sink_params_ = new_sink_params; |
669 } | 659 } |
670 | 660 |
671 // Specify the latency info to be passed to the browser side. | 661 // Specify the latency info to be passed to the browser side. |
672 new_sink_params.set_latency_tag(AudioDeviceFactory::GetSourceLatencyType( | 662 new_sink_params.set_latency_tag(AudioDeviceFactory::GetSourceLatencyType( |
673 AudioDeviceFactory::AudioDeviceFactory::kSourceWebRtc)); | 663 AudioDeviceFactory::AudioDeviceFactory::kSourceWebRtc)); |
674 sink_->Initialize(new_sink_params, this); | 664 sink_->Initialize(new_sink_params, this); |
675 } | 665 } |
676 | 666 |
677 } // namespace content | 667 } // namespace content |
OLD | NEW |