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

Side by Side Diff: content/renderer/media/webrtc_audio_renderer.cc

Issue 1596523005: Drop WebRTC audio data if OS has skipped frames. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Code review (peah@) + rebase. Created 4 years, 11 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 (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
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
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) {
441 audio_fifo_.reset(new media::AudioPullFifo(
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());
451 else
452 SourceCallback(0, drop_bus.get());
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 &current_time_); 488 &current_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 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 sample_rate = 48000; 620 sample_rate = 48000;
600 } 621 }
601 media::AudioSampleRate asr; 622 media::AudioSampleRate asr;
602 if (media::ToAudioSampleRate(sample_rate, &asr)) { 623 if (media::ToAudioSampleRate(sample_rate, &asr)) {
603 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputSampleRate", asr, 624 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputSampleRate", asr,
604 media::kAudioSampleRateMax + 1); 625 media::kAudioSampleRateMax + 1);
605 } else { 626 } else {
606 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected", sample_rate); 627 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected", sample_rate);
607 } 628 }
608 629
609 // Set up audio parameters for the source, i.e., the WebRTC client. 630 // Set up audio parameters for the source, i.e. the WebRTC client.
610
611 // The WebRTC client only supports multiples of 10ms as buffer size where 631 // The WebRTC client only supports multiples of 10ms as buffer size where
612 // 10ms is preferred for lowest possible delay. 632 // 10ms is preferred for lowest possible delay.
613 const int frames_per_10ms = (sample_rate / 100); 633 const int frames_per_10ms = (sample_rate / 100);
614 DVLOG(1) << "Using WebRTC output buffer size: " << frames_per_10ms; 634 DVLOG(1) << "Using WebRTC output buffer size: " << frames_per_10ms;
615 media::AudioParameters source_params( 635 media::AudioParameters source_params(
616 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 636 media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
617 new_sink_params.channel_layout(), sample_rate, 16, frames_per_10ms); 637 new_sink_params.channel_layout(), sample_rate, 16, frames_per_10ms);
618 source_params.set_channels_for_discrete(new_sink_params.channels()); 638 source_params.set_channels_for_discrete(new_sink_params.channels());
619 639
620 const int frames_per_buffer = GetOptimalBufferSize( 640 const int frames_per_buffer = GetOptimalBufferSize(
621 sample_rate, sink_->GetOutputParameters().frames_per_buffer()); 641 sample_rate, sink_->GetOutputParameters().frames_per_buffer());
622 642
623 new_sink_params.Reset( 643 new_sink_params.Reset(
624 new_sink_params.format(), new_sink_params.channel_layout(), 644 new_sink_params.format(), new_sink_params.channel_layout(),
625 sample_rate, 16, frames_per_buffer); 645 sample_rate, 16, frames_per_buffer);
626 646
627 // Create a FIFO if re-buffering is required to match the source input with 647 // 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 648 // the sink request. The source acts as provider here and the sink as
629 // consumer. 649 // consumer.
630 int new_fifo_delay_milliseconds = 0; 650 const bool different_source_sink_frames =
631 scoped_ptr<media::AudioPullFifo> new_audio_fifo; 651 source_params.frames_per_buffer() != new_sink_params.frames_per_buffer();
632 if (source_params.frames_per_buffer() != 652 if (different_source_sink_frames) {
633 new_sink_params.frames_per_buffer()) {
634 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer() 653 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer()
635 << " to " << new_sink_params.frames_per_buffer(); 654 << " 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 } 655 }
651 656
652 { 657 {
653 base::AutoLock lock(lock_); 658 base::AutoLock lock(lock_);
659 if ((!audio_fifo_ && different_source_sink_frames) ||
660 (audio_fifo_ &&
661 audio_fifo_->SizeInFrames() != source_params.frames_per_buffer())) {
662 audio_fifo_.reset(new media::AudioPullFifo(
663 source_params.channels(), source_params.frames_per_buffer(),
664 base::Bind(&WebRtcAudioRenderer::SourceCallback,
665 base::Unretained(this))));
666 }
654 sink_params_ = new_sink_params; 667 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 } 668 }
659 669
660 sink_->Initialize(new_sink_params, this); 670 sink_->Initialize(new_sink_params, this);
661 } 671 }
662 672
663 } // namespace content 673 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698