#include "base/metrics/histogram.h"
#include "base/synchronization/lock.h"
#include "content/renderer/media/audio_device_factory.h"
+#include "content/renderer/media/media_stream_dispatcher.h"
#include "content/renderer/media/webrtc_audio_capturer.h"
+#include "content/renderer/media/webrtc_audio_renderer.h"
+#include "content/renderer/render_frame_impl.h"
#include "media/audio/audio_output_device.h"
+#include "media/base/audio_block_fifo.h"
#include "media/base/audio_bus.h"
-#include "media/base/audio_fifo.h"
namespace content {
// Provide data by reading from the FIFO if the FIFO contains enough
// to fulfill the request.
- if (loopback_fifo_->frames() >= audio_bus->frames()) {
- loopback_fifo_->Consume(audio_bus, 0, audio_bus->frames());
+ if (loopback_fifo_->available_blocks()) {
+ const media::AudioBus* audio_data = loopback_fifo_->Consume();
+ DCHECK_EQ(audio_data->frames(), audio_bus->frames());
+ audio_data->CopyTo(audio_bus);
} else {
audio_bus->Zero();
// This warning is perfectly safe if it happens for the first audio
return;
// Push captured audio to FIFO so it can be read by a local sink.
- if (loopback_fifo_->frames() + number_of_frames <=
- loopback_fifo_->max_frames()) {
- scoped_ptr<media::AudioBus> audio_source = media::AudioBus::Create(
- number_of_channels, number_of_frames);
- audio_source->FromInterleaved(audio_data,
- audio_source->frames(),
- sizeof(audio_data[0]));
- loopback_fifo_->Push(audio_source.get());
+ if (loopback_fifo_->GetUnfilledFrames() >= number_of_frames) {
+ loopback_fifo_->Push(audio_data, number_of_frames, sizeof(audio_data[0]));
const base::TimeTicks now = base::TimeTicks::Now();
total_render_time_ += now - last_render_time_;
capture_thread_checker_.DetachFromThread();
DCHECK(capture_thread_checker_.CalledOnValidThread());
- // Reset the |source_params_|, |sink_params_| and |loopback_fifo_| to match
- // the new format.
- {
- base::AutoLock auto_lock(thread_lock_);
- if (source_params_ == params)
- return;
-
- source_params_ = params;
-
- sink_params_ = media::AudioParameters(source_params_.format(),
- source_params_.channel_layout(), source_params_.channels(),
- source_params_.input_channels(), source_params_.sample_rate(),
- source_params_.bits_per_sample(),
-#if defined(OS_ANDROID)
- // On Android, input and output use the same sample rate. In order to
- // use the low latency mode, we need to use the buffer size suggested by
- // the AudioManager for the sink. It will later be used to decide
- // the buffer size of the shared memory buffer.
- frames_per_buffer_,
-#else
- 2 * source_params_.frames_per_buffer(),
-#endif
- // If DUCKING is enabled on the source, it needs to be enabled on the
- // sink as well.
- source_params_.effects());
-
- // TODO(henrika): we could add a more dynamic solution here but I prefer
- // a fixed size combined with bad audio at overflow. The alternative is
- // that we start to build up latency and that can be more difficult to
- // detect. Tests have shown that the FIFO never contains more than 2 or 3
- // audio frames but I have selected a max size of ten buffers just
- // in case since these tests were performed on a 16 core, 64GB Win 7
- // machine. We could also add some sort of error notifier in this area if
- // the FIFO overflows.
- loopback_fifo_.reset(new media::AudioFifo(
- params.channels(), 10 * params.frames_per_buffer()));
- }
-
// Post a task on the main render thread to reconfigure the |sink_| with the
// new format.
message_loop_->PostTask(
// Stop the output audio stream, i.e, stop asking for data to render.
// It is safer to call Stop() on the |sink_| to clean up the resources even
// when the |sink_| is never started.
- if (sink_) {
+ if (sink_.get()) {
sink_->Stop();
sink_ = NULL;
}
if (!sink_.get() || !source_params_.IsValid())
return;
- base::AutoLock auto_lock(thread_lock_);
-
- // Clear up the old data in the FIFO.
- loopback_fifo_->Clear();
+ {
+ // Clear up the old data in the FIFO.
+ base::AutoLock auto_lock(thread_lock_);
+ loopback_fifo_->Clear();
+ }
if (!sink_params_.IsValid() || !playing_ || !volume_ || sink_started_)
return;
DVLOG(1) << "WebRtcLocalAudioRenderer::MaybeStartSink() -- Starting sink_.";
- sink_->InitializeUnifiedStream(sink_params_, this, session_id_);
+ sink_->InitializeWithSessionId(sink_params_, this, session_id_);
sink_->Start();
sink_started_ = true;
UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates",
DVLOG(1) << "WebRtcLocalAudioRenderer::ReconfigureSink()";
- if (!sink_)
+ int implicit_ducking_effect = 0;
+ RenderFrameImpl* const frame =
+ RenderFrameImpl::FromRoutingID(source_render_frame_id_);
+ MediaStreamDispatcher* const dispatcher = frame ?
+ frame->GetMediaStreamDispatcher() : NULL;
+ if (dispatcher && dispatcher->IsAudioDuckingActive()) {
+ DVLOG(1) << "Forcing DUCKING to be ON for output";
+ implicit_ducking_effect = media::AudioParameters::DUCKING;
+ } else {
+ DVLOG(1) << "DUCKING not forced ON for output";
+ }
+
+ if (source_params_.Equals(params))
+ return;
+
+ // Reset the |source_params_|, |sink_params_| and |loopback_fifo_| to match
+ // the new format.
+
+ source_params_ = params;
+
+ sink_params_ = media::AudioParameters(source_params_.format(),
+ source_params_.channel_layout(), source_params_.sample_rate(),
+ source_params_.bits_per_sample(),
+ WebRtcAudioRenderer::GetOptimalBufferSize(source_params_.sample_rate(),
+ frames_per_buffer_),
+ // If DUCKING is enabled on the source, it needs to be enabled on the
+ // sink as well.
+ source_params_.effects() | implicit_ducking_effect);
+
+ {
+ // TODO(henrika): we could add a more dynamic solution here but I prefer
+ // a fixed size combined with bad audio at overflow. The alternative is
+ // that we start to build up latency and that can be more difficult to
+ // detect. Tests have shown that the FIFO never contains more than 2 or 3
+ // audio frames but I have selected a max size of ten buffers just
+ // in case since these tests were performed on a 16 core, 64GB Win 7
+ // machine. We could also add some sort of error notifier in this area if
+ // the FIFO overflows.
+ const int blocks_of_buffers =
+ 10 * params.frames_per_buffer() / sink_params_.frames_per_buffer() + 1;
+ media::AudioBlockFifo* new_fifo = new media::AudioBlockFifo(
+ params.channels(), sink_params_.frames_per_buffer(), blocks_of_buffers);
+
+ base::AutoLock auto_lock(thread_lock_);
+ loopback_fifo_.reset(new_fifo);
+ }
+
+ if (!sink_.get())
return; // WebRtcLocalAudioRenderer has not yet been started.
// Stop |sink_| and re-create a new one to be initialized with different audio
sink_->Stop();
sink_started_ = false;
}
+
sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_,
source_render_frame_id_);
MaybeStartSink();