Chromium Code Reviews| 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/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 const url::Origin& security_origin) | 180 const url::Origin& security_origin) |
| 181 : state_(UNINITIALIZED), | 181 : state_(UNINITIALIZED), |
| 182 source_render_frame_id_(source_render_frame_id), | 182 source_render_frame_id_(source_render_frame_id), |
| 183 session_id_(session_id), | 183 session_id_(session_id), |
| 184 signaling_thread_(signaling_thread), | 184 signaling_thread_(signaling_thread), |
| 185 media_stream_(media_stream), | 185 media_stream_(media_stream), |
| 186 source_(NULL), | 186 source_(NULL), |
| 187 play_ref_count_(0), | 187 play_ref_count_(0), |
| 188 start_ref_count_(0), | 188 start_ref_count_(0), |
| 189 audio_delay_milliseconds_(0), | 189 audio_delay_milliseconds_(0), |
| 190 fifo_delay_milliseconds_(0), | |
| 191 sink_params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | 190 sink_params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 192 media::CHANNEL_LAYOUT_STEREO, | 191 media::CHANNEL_LAYOUT_STEREO, |
| 193 0, | 192 0, |
| 194 16, | 193 16, |
| 195 0), | 194 0), |
| 196 output_device_id_(device_id), | 195 output_device_id_(device_id), |
| 197 security_origin_(security_origin), | 196 security_origin_(security_origin), |
| 198 render_callback_count_(0) { | 197 render_callback_count_(0) { |
| 199 WebRtcLogMessage(base::StringPrintf( | 198 WebRtcLogMessage(base::StringPrintf( |
| 200 "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i", | 199 "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i", |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 base::AutoLock auto_lock(lock_); | 426 base::AutoLock auto_lock(lock_); |
| 428 if (!source_) | 427 if (!source_) |
| 429 return 0; | 428 return 0; |
| 430 | 429 |
| 431 DVLOG(2) << "WebRtcAudioRenderer::Render()"; | 430 DVLOG(2) << "WebRtcAudioRenderer::Render()"; |
| 432 DVLOG(2) << "audio_delay_milliseconds: " << audio_delay_milliseconds; | 431 DVLOG(2) << "audio_delay_milliseconds: " << audio_delay_milliseconds; |
| 433 | 432 |
| 434 DCHECK_LE(audio_delay_milliseconds, static_cast<uint32_t>(INT_MAX)); | 433 DCHECK_LE(audio_delay_milliseconds, static_cast<uint32_t>(INT_MAX)); |
| 435 audio_delay_milliseconds_ = static_cast<int>(audio_delay_milliseconds); | 434 audio_delay_milliseconds_ = static_cast<int>(audio_delay_milliseconds); |
| 436 | 435 |
| 436 // If there are skipped frames, pull and throw away the same amount. | |
| 437 if (frames_skipped > 0) { | |
| 438 const uint32_t frames_per_10ms = | |
| 439 static_cast<uint32_t>(sink_params_.sample_rate() / 100); | |
| 440 if (!audio_fifo_ && frames_skipped != frames_per_10ms) { | |
|
peah
2016/01/19 10:13:52
What happens if frames_skipped > frames_per_10_ms.
Henrik Grunell
2016/01/19 13:03:41
Yes, the fifo will handle that.
peah
2016/01/20 15:16:47
I think that one of the things I don't understand
Henrik Grunell
2016/01/21 08:55:46
Since we always pull 10 ms of data from the source
peah
2016/01/21 09:16:25
Great! Thanks for the explanation! I have one more
Henrik Grunell
2016/01/21 12:26:16
Any time. :) It can contain 0. Data is only pulled
| |
| 441 audio_fifo_.reset(new media::AudioPullFifo( | |
|
peah
2016/01/19 10:13:52
One thing I don't really get is the recreation of
Henrik Grunell
2016/01/19 13:03:41
The |source_params| frames_per_buffer always corre
peah
2016/01/21 09:16:25
Since it always holds that
source_params.frames_p
Henrik Grunell
2016/01/21 12:26:16
Yes source_params.frames_per_buffer()==frames_per_
| |
| 442 sink_params_.channels(), frames_per_10ms, | |
| 443 base::Bind(&WebRtcAudioRenderer::SourceCallback, | |
| 444 base::Unretained(this)))); | |
| 445 } | |
| 446 | |
| 447 scoped_ptr<media::AudioBus> drop_bus = | |
| 448 media::AudioBus::Create(audio_bus->channels(), frames_skipped); | |
| 449 if (audio_fifo_) | |
| 450 audio_fifo_->Consume(drop_bus.get(), drop_bus->frames()); | |
|
peah
2016/01/19 10:13:52
How does this work? Does it consume audio_fifo_->S
Henrik Grunell
2016/01/19 13:03:41
It consumes drop_bus->frames() frames.
| |
| 451 else | |
| 452 SourceCallback(0, drop_bus.get()); | |
|
peah
2016/01/19 10:13:52
To me this is a bit strange. Please correct me if
Henrik Grunell
2016/01/19 13:03:41
I sure will. ;)
| |
| 453 } | |
| 454 | |
| 455 // Pull the data we will deliver. | |
| 437 if (audio_fifo_) | 456 if (audio_fifo_) |
| 438 audio_fifo_->Consume(audio_bus, audio_bus->frames()); | 457 audio_fifo_->Consume(audio_bus, audio_bus->frames()); |
| 439 else | 458 else |
| 440 SourceCallback(0, audio_bus); | 459 SourceCallback(0, audio_bus); |
| 441 | 460 |
| 442 return (state_ == PLAYING) ? audio_bus->frames() : 0; | 461 return (state_ == PLAYING) ? audio_bus->frames() : 0; |
| 443 } | 462 } |
| 444 | 463 |
| 445 void WebRtcAudioRenderer::OnRenderError() { | 464 void WebRtcAudioRenderer::OnRenderError() { |
| 446 NOTIMPLEMENTED(); | 465 NOTIMPLEMENTED(); |
| 447 LOG(ERROR) << "OnRenderError()"; | 466 LOG(ERROR) << "OnRenderError()"; |
| 448 } | 467 } |
| 449 | 468 |
| 450 // Called by AudioPullFifo when more data is necessary. | 469 // Called by AudioPullFifo when more data is necessary. |
| 451 void WebRtcAudioRenderer::SourceCallback( | 470 void WebRtcAudioRenderer::SourceCallback( |
| 452 int fifo_frame_delay, media::AudioBus* audio_bus) { | 471 int fifo_frame_delay, media::AudioBus* audio_bus) { |
| 453 DCHECK(audio_renderer_thread_checker_.CalledOnValidThread()); | 472 DCHECK(audio_renderer_thread_checker_.CalledOnValidThread()); |
| 454 base::TimeTicks start_time = base::TimeTicks::Now(); | 473 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 455 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" | 474 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" |
| 456 << fifo_frame_delay << ", " | 475 << fifo_frame_delay << ", " |
| 457 << audio_bus->frames() << ")"; | 476 << audio_bus->frames() << ")"; |
| 458 | 477 |
| 459 int output_delay_milliseconds = audio_delay_milliseconds_; | 478 int output_delay_milliseconds = audio_delay_milliseconds_; |
| 460 output_delay_milliseconds += fifo_delay_milliseconds_; | 479 output_delay_milliseconds += fifo_frame_delay * |
| 480 base::Time::kMillisecondsPerSecond / | |
| 481 sink_params_.sample_rate(); | |
| 461 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; | 482 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; |
| 462 | 483 |
| 463 // We need to keep render data for the |source_| regardless of |state_|, | 484 // We need to keep render data for the |source_| regardless of |state_|, |
| 464 // otherwise the data will be buffered up inside |source_|. | 485 // otherwise the data will be buffered up inside |source_|. |
| 465 source_->RenderData(audio_bus, sink_params_.sample_rate(), | 486 source_->RenderData(audio_bus, sink_params_.sample_rate(), |
| 466 output_delay_milliseconds, | 487 output_delay_milliseconds, |
| 467 ¤t_time_); | 488 ¤t_time_); |
| 468 | 489 |
| 469 // Avoid filling up the audio bus if we are not playing; instead | 490 // Avoid filling up the audio bus if we are not playing; instead |
| 470 // return here and ensure that the returned value in Render() is 0. | 491 // return here and ensure that the returned value in Render() is 0. |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 620 const int frames_per_buffer = GetOptimalBufferSize( | 641 const int frames_per_buffer = GetOptimalBufferSize( |
| 621 sample_rate, sink_->GetOutputParameters().frames_per_buffer()); | 642 sample_rate, sink_->GetOutputParameters().frames_per_buffer()); |
| 622 | 643 |
| 623 new_sink_params.Reset( | 644 new_sink_params.Reset( |
| 624 new_sink_params.format(), new_sink_params.channel_layout(), | 645 new_sink_params.format(), new_sink_params.channel_layout(), |
| 625 sample_rate, 16, frames_per_buffer); | 646 sample_rate, 16, frames_per_buffer); |
| 626 | 647 |
| 627 // Create a FIFO if re-buffering is required to match the source input with | 648 // Create a FIFO if re-buffering is required to match the source input with |
| 628 // the sink request. The source acts as provider here and the sink as | 649 // the sink request. The source acts as provider here and the sink as |
| 629 // consumer. | 650 // consumer. |
| 630 int new_fifo_delay_milliseconds = 0; | |
| 631 scoped_ptr<media::AudioPullFifo> new_audio_fifo; | 651 scoped_ptr<media::AudioPullFifo> new_audio_fifo; |
|
peah
2016/01/19 10:13:52
This seems to be unused after the change. Is that
Henrik Grunell
2016/01/19 13:03:41
Very much so. Removed.
| |
| 632 if (source_params.frames_per_buffer() != | 652 const bool different_source_sink_frames = |
| 633 new_sink_params.frames_per_buffer()) { | 653 source_params.frames_per_buffer() != new_sink_params.frames_per_buffer(); |
| 654 if (different_source_sink_frames) { | |
| 634 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer() | 655 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer() |
| 635 << " to " << new_sink_params.frames_per_buffer(); | 656 << " to " << new_sink_params.frames_per_buffer(); |
| 636 new_audio_fifo.reset(new media::AudioPullFifo( | |
| 637 source_params.channels(), source_params.frames_per_buffer(), | |
| 638 base::Bind(&WebRtcAudioRenderer::SourceCallback, | |
| 639 base::Unretained(this)))); | |
| 640 | |
| 641 if (new_sink_params.frames_per_buffer() > | |
| 642 source_params.frames_per_buffer()) { | |
| 643 int frame_duration_milliseconds = | |
| 644 base::Time::kMillisecondsPerSecond / | |
| 645 static_cast<double>(source_params.sample_rate()); | |
| 646 new_fifo_delay_milliseconds = (new_sink_params.frames_per_buffer() - | |
| 647 source_params.frames_per_buffer()) * | |
| 648 frame_duration_milliseconds; | |
| 649 } | |
| 650 } | 657 } |
| 651 | 658 |
| 652 { | 659 { |
| 653 base::AutoLock lock(lock_); | 660 base::AutoLock lock(lock_); |
| 661 if ((!audio_fifo_ && different_source_sink_frames) || | |
| 662 (audio_fifo_ && | |
| 663 audio_fifo_->SizeInFrames() != source_params.frames_per_buffer())) { | |
| 664 audio_fifo_.reset(new media::AudioPullFifo( | |
| 665 source_params.channels(), source_params.frames_per_buffer(), | |
| 666 base::Bind(&WebRtcAudioRenderer::SourceCallback, | |
| 667 base::Unretained(this)))); | |
| 668 } | |
| 654 sink_params_ = new_sink_params; | 669 sink_params_ = new_sink_params; |
| 655 fifo_delay_milliseconds_ = new_fifo_delay_milliseconds; | |
| 656 if (new_audio_fifo.get()) | |
| 657 audio_fifo_ = std::move(new_audio_fifo); | |
| 658 } | 670 } |
| 659 | 671 |
| 660 sink_->Initialize(new_sink_params, this); | 672 sink_->Initialize(new_sink_params, this); |
| 661 } | 673 } |
| 662 | 674 |
| 663 } // namespace content | 675 } // namespace content |
| OLD | NEW |