Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / webrtc_local_audio_renderer.cc
index 53aad23..dd657eb 100644 (file)
 #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 {
 
@@ -40,8 +43,10 @@ int WebRtcLocalAudioRenderer::Render(
 
   // 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
@@ -68,14 +73,8 @@ void WebRtcLocalAudioRenderer::OnData(const int16* audio_data,
     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_;
@@ -93,44 +92,6 @@ void WebRtcLocalAudioRenderer::OnSetFormat(
   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(
@@ -193,7 +154,7 @@ void WebRtcLocalAudioRenderer::Stop() {
   // 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;
   }
@@ -278,16 +239,17 @@ void WebRtcLocalAudioRenderer::MaybeStartSink() {
   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",
@@ -300,7 +262,54 @@ void WebRtcLocalAudioRenderer::ReconfigureSink(
 
   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
@@ -309,6 +318,7 @@ void WebRtcLocalAudioRenderer::ReconfigureSink(
     sink_->Stop();
     sink_started_ = false;
   }
+
   sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_,
                                               source_render_frame_id_);
   MaybeStartSink();