Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / media / filters / audio_renderer_impl.cc
index acb43f7..faec58e 100644 (file)
@@ -20,6 +20,7 @@
 #include "media/base/audio_splicer.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/demuxer_stream.h"
+#include "media/filters/audio_clock.h"
 #include "media/filters/decrypting_demuxer_stream.h"
 
 namespace media {
@@ -57,8 +58,6 @@ AudioRendererImpl::AudioRendererImpl(
       pending_read_(false),
       received_end_of_stream_(false),
       rendered_end_of_stream_(false),
-      audio_time_buffered_(kNoTimestamp()),
-      current_time_(kNoTimestamp()),
       underflow_disabled_(false),
       preroll_aborted_(false),
       weak_factory_(this) {
@@ -169,8 +168,7 @@ void AudioRendererImpl::ResetDecoderDone() {
     DCHECK_EQ(state_, kPaused);
     DCHECK(!flush_cb_.is_null());
 
-    audio_time_buffered_ = kNoTimestamp();
-    current_time_ = kNoTimestamp();
+    audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate()));
     received_end_of_stream_ = false;
     rendered_end_of_stream_ = false;
     preroll_aborted_ = false;
@@ -237,7 +235,6 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream,
                                    const base::Closure& underflow_cb,
                                    const TimeCB& time_cb,
                                    const base::Closure& ended_cb,
-                                   const base::Closure& disabled_cb,
                                    const PipelineStatusCB& error_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(stream);
@@ -247,7 +244,6 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream,
   DCHECK(!underflow_cb.is_null());
   DCHECK(!time_cb.is_null());
   DCHECK(!ended_cb.is_null());
-  DCHECK(!disabled_cb.is_null());
   DCHECK(!error_cb.is_null());
   DCHECK_EQ(kUninitialized, state_);
   DCHECK(sink_);
@@ -258,7 +254,6 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream,
   underflow_cb_ = underflow_cb;
   time_cb_ = time_cb;
   ended_cb_ = ended_cb;
-  disabled_cb_ = disabled_cb;
   error_cb_ = error_cb;
 
   expecting_config_changes_ = stream->SupportsConfigChanges();
@@ -278,11 +273,21 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream,
     buffer_converter_.reset();
   } else {
     // TODO(rileya): Support hardware config changes
-    audio_parameters_ = hardware_config_->GetOutputConfig();
+    const AudioParameters& hw_params = hardware_config_->GetOutputConfig();
+    audio_parameters_.Reset(hw_params.format(),
+                            hw_params.channel_layout(),
+                            hw_params.channels(),
+                            hw_params.input_channels(),
+                            hw_params.sample_rate(),
+                            hw_params.bits_per_sample(),
+                            hardware_config_->GetHighLatencyBufferSize());
   }
 
+  audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate()));
+
   audio_buffer_stream_.Initialize(
       stream,
+      false,
       statistics_cb,
       base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized,
                  weak_factory_.GetWeakPtr()));
@@ -557,27 +562,33 @@ bool AudioRendererImpl::IsBeforePrerollTime(
 int AudioRendererImpl::Render(AudioBus* audio_bus,
                               int audio_delay_milliseconds) {
   const int requested_frames = audio_bus->frames();
-  base::TimeDelta current_time = kNoTimestamp();
-  base::TimeDelta max_time = kNoTimestamp();
   base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds(
       audio_delay_milliseconds);
-
+  const int delay_frames = static_cast<int>(playback_delay.InSecondsF() *
+                                            audio_parameters_.sample_rate());
   int frames_written = 0;
+  base::Closure time_cb;
   base::Closure underflow_cb;
   {
     base::AutoLock auto_lock(lock_);
 
     // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
-    if (!algorithm_)
+    if (!algorithm_) {
+      audio_clock_->WroteSilence(requested_frames, delay_frames);
       return 0;
+    }
 
     float playback_rate = algorithm_->playback_rate();
-    if (playback_rate == 0)
+    if (playback_rate == 0) {
+      audio_clock_->WroteSilence(requested_frames, delay_frames);
       return 0;
+    }
 
     // Mute audio by returning 0 when not playing.
-    if (state_ != kPlaying)
+    if (state_ != kPlaying) {
+      audio_clock_->WroteSilence(requested_frames, delay_frames);
       return 0;
+    }
 
     // We use the following conditions to determine end of playback:
     //   1) Algorithm can not fill the audio callback buffer
@@ -594,7 +605,15 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
     //   3) We are in the kPlaying state
     //
     // Otherwise the buffer has data we can send to the device.
-    frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
+    const base::TimeDelta media_timestamp_before_filling =
+        audio_clock_->CurrentMediaTimestamp();
+    if (algorithm_->frames_buffered() > 0) {
+      frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
+      audio_clock_->WroteAudio(
+          frames_written, delay_frames, playback_rate, algorithm_->GetTime());
+    }
+    audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames);
+
     if (frames_written == 0) {
       const base::TimeTicks now = now_cb_.Run();
 
@@ -619,51 +638,24 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
                                         weak_factory_.GetWeakPtr()));
     }
 
-    // The |audio_time_buffered_| is the ending timestamp of the last frame
-    // buffered at the audio device. |playback_delay| is the amount of time
-    // buffered at the audio device. The current time can be computed by their
-    // difference.
-    if (audio_time_buffered_ != kNoTimestamp()) {
-      // Adjust the delay according to playback rate.
-      base::TimeDelta adjusted_playback_delay =
-          base::TimeDelta::FromMicroseconds(ceil(
-              playback_delay.InMicroseconds() * playback_rate));
-
-      base::TimeDelta previous_time = current_time_;
-      current_time_ = audio_time_buffered_ - adjusted_playback_delay;
-
-      // Time can change in one of two ways:
-      //   1) The time of the audio data at the audio device changed, or
-      //   2) The playback delay value has changed
-      //
-      // We only want to set |current_time| (and thus execute |time_cb_|) if
-      // time has progressed and we haven't signaled end of stream yet.
-      //
-      // Why? The current latency of the system results in getting the last call
-      // to FillBuffer() later than we'd like, which delays firing the 'ended'
-      // event, which delays the looping/trigging performance of short sound
-      // effects.
-      //
-      // TODO(scherkus): revisit this and switch back to relying on playback
-      // delay after we've revamped our audio IPC subsystem.
-      if (current_time_ > previous_time && !rendered_end_of_stream_) {
-        current_time = current_time_;
-      }
+    // We only want to execute |time_cb_| if time has progressed and we haven't
+    // signaled end of stream yet.
+    if (media_timestamp_before_filling !=
+            audio_clock_->CurrentMediaTimestamp() &&
+        !rendered_end_of_stream_) {
+      time_cb = base::Bind(time_cb_,
+                           audio_clock_->CurrentMediaTimestamp(),
+                           audio_clock_->last_endpoint_timestamp());
     }
 
-    // The call to FillBuffer() on |algorithm_| has increased the amount of
-    // buffered audio data. Update the new amount of time buffered.
-    max_time = algorithm_->GetTime();
-    audio_time_buffered_ = max_time;
-
     if (frames_written > 0) {
       UpdateEarliestEndTime_Locked(
           frames_written, playback_delay, now_cb_.Run());
     }
   }
 
-  if (current_time != kNoTimestamp() && max_time != kNoTimestamp())
-    time_cb_.Run(current_time, max_time);
+  if (!time_cb.is_null())
+    time_cb.Run();
 
   if (!underflow_cb.is_null())
     underflow_cb.Run();
@@ -687,8 +679,12 @@ void AudioRendererImpl::UpdateEarliestEndTime_Locked(
 }
 
 void AudioRendererImpl::OnRenderError() {
+  // UMA data tells us this happens ~0.01% of the time. Trigger an error instead
+  // of trying to gracefully fall back to a fake sink. It's very likely
+  // OnRenderError() should be removed and the audio stack handle errors without
+  // notifying clients. See http://crbug.com/234708 for details.
   HistogramRendererEvent(RENDER_ERROR);
-  disabled_cb_.Run();
+  error_cb_.Run(PIPELINE_ERROR_DECODE);
 }
 
 void AudioRendererImpl::DisableUnderflowForTesting() {
@@ -750,6 +746,11 @@ void AudioRendererImpl::OnConfigChange() {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(expecting_config_changes_);
   buffer_converter_->ResetTimestampState();
+  // Drain flushed buffers from the converter so the AudioSplicer receives all
+  // data ahead of any OnNewSpliceBuffer() calls.  Since discontinuities should
+  // only appear after config changes, AddInput() should never fail here.
+  while (buffer_converter_->HasNextBuffer())
+    CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer()));
 }
 
 }  // namespace media