Home | History | Annotate | Download | only in filters
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/filters/audio_clock.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/logging.h"
     10 #include "media/base/buffers.h"
     11 
     12 namespace media {
     13 
     14 AudioClock::AudioClock(base::TimeDelta start_timestamp, int sample_rate)
     15     : start_timestamp_(start_timestamp),
     16       sample_rate_(sample_rate),
     17       microseconds_per_frame_(
     18           static_cast<double>(base::Time::kMicrosecondsPerSecond) /
     19           sample_rate),
     20       total_buffered_frames_(0),
     21       front_timestamp_(start_timestamp),
     22       back_timestamp_(start_timestamp) {
     23 }
     24 
     25 AudioClock::~AudioClock() {
     26 }
     27 
     28 void AudioClock::WroteAudio(int frames_written,
     29                             int frames_requested,
     30                             int delay_frames,
     31                             float playback_rate) {
     32   DCHECK_GE(frames_written, 0);
     33   DCHECK_LE(frames_written, frames_requested);
     34   DCHECK_GE(delay_frames, 0);
     35   DCHECK_GE(playback_rate, 0);
     36 
     37   // First write: initialize buffer with silence.
     38   if (start_timestamp_ == front_timestamp_ && buffered_.empty())
     39     PushBufferedAudioData(delay_frames, 0.0f);
     40 
     41   // Move frames from |buffered_| into the computed timestamp based on
     42   // |delay_frames|.
     43   //
     44   // The ordering of compute -> push -> pop eliminates unnecessary memory
     45   // reallocations in cases where |buffered_| gets emptied.
     46   int64_t frames_played =
     47       std::max(INT64_C(0), total_buffered_frames_ - delay_frames);
     48   front_timestamp_ += ComputeBufferedMediaTime(frames_played);
     49   PushBufferedAudioData(frames_written, playback_rate);
     50   PushBufferedAudioData(frames_requested - frames_written, 0.0f);
     51   PopBufferedAudioData(frames_played);
     52 
     53   back_timestamp_ += base::TimeDelta::FromMicroseconds(
     54       frames_written * playback_rate * microseconds_per_frame_);
     55 
     56   // Update cached values.
     57   double scaled_frames = 0;
     58   double scaled_frames_at_same_rate = 0;
     59   bool found_silence = false;
     60   for (size_t i = 0; i < buffered_.size(); ++i) {
     61     if (buffered_[i].playback_rate == 0) {
     62       found_silence = true;
     63       continue;
     64     }
     65 
     66     // Any buffered silence breaks our contiguous stretch of audio data.
     67     if (found_silence)
     68       break;
     69 
     70     scaled_frames += (buffered_[i].frames * buffered_[i].playback_rate);
     71 
     72     if (i == 0)
     73       scaled_frames_at_same_rate = scaled_frames;
     74   }
     75 
     76   contiguous_audio_data_buffered_ = base::TimeDelta::FromMicroseconds(
     77       scaled_frames * microseconds_per_frame_);
     78   contiguous_audio_data_buffered_at_same_rate_ =
     79       base::TimeDelta::FromMicroseconds(scaled_frames_at_same_rate *
     80                                         microseconds_per_frame_);
     81 }
     82 
     83 base::TimeDelta AudioClock::TimestampSinceWriting(
     84     base::TimeDelta time_since_writing) const {
     85   int64_t frames_played_since_writing = std::min(
     86       total_buffered_frames_,
     87       static_cast<int64_t>(time_since_writing.InSecondsF() * sample_rate_));
     88   return front_timestamp_ +
     89          ComputeBufferedMediaTime(frames_played_since_writing);
     90 }
     91 
     92 base::TimeDelta AudioClock::TimeUntilPlayback(base::TimeDelta timestamp) const {
     93   DCHECK(timestamp >= front_timestamp_);
     94   DCHECK(timestamp <= back_timestamp_);
     95 
     96   int64_t frames_until_timestamp = 0;
     97   double timestamp_us = timestamp.InMicroseconds();
     98   double media_time_us = front_timestamp_.InMicroseconds();
     99 
    100   for (size_t i = 0; i < buffered_.size(); ++i) {
    101     // Leading silence is always accounted prior to anything else.
    102     if (buffered_[i].playback_rate == 0) {
    103       frames_until_timestamp += buffered_[i].frames;
    104       continue;
    105     }
    106 
    107     // Calculate upper bound on media time for current block of buffered frames.
    108     double delta_us = buffered_[i].frames * buffered_[i].playback_rate *
    109                       microseconds_per_frame_;
    110     double max_media_time_us = media_time_us + delta_us;
    111 
    112     // Determine amount of media time to convert to frames for current block. If
    113     // target timestamp falls within current block, scale the amount of frames
    114     // based on remaining amount of media time.
    115     if (timestamp_us <= max_media_time_us) {
    116       frames_until_timestamp +=
    117           buffered_[i].frames * (timestamp_us - media_time_us) / delta_us;
    118       break;
    119     }
    120 
    121     media_time_us = max_media_time_us;
    122     frames_until_timestamp += buffered_[i].frames;
    123   }
    124 
    125   return base::TimeDelta::FromMicroseconds(frames_until_timestamp *
    126                                            microseconds_per_frame_);
    127 }
    128 
    129 AudioClock::AudioData::AudioData(int64_t frames, float playback_rate)
    130     : frames(frames), playback_rate(playback_rate) {
    131 }
    132 
    133 void AudioClock::PushBufferedAudioData(int64_t frames, float playback_rate) {
    134   if (frames == 0)
    135     return;
    136 
    137   total_buffered_frames_ += frames;
    138 
    139   // Avoid creating extra elements where possible.
    140   if (!buffered_.empty() && buffered_.back().playback_rate == playback_rate) {
    141     buffered_.back().frames += frames;
    142     return;
    143   }
    144 
    145   buffered_.push_back(AudioData(frames, playback_rate));
    146 }
    147 
    148 void AudioClock::PopBufferedAudioData(int64_t frames) {
    149   DCHECK_LE(frames, total_buffered_frames_);
    150 
    151   total_buffered_frames_ -= frames;
    152 
    153   while (frames > 0) {
    154     int64_t frames_to_pop = std::min(buffered_.front().frames, frames);
    155     buffered_.front().frames -= frames_to_pop;
    156     if (buffered_.front().frames == 0)
    157       buffered_.pop_front();
    158 
    159     frames -= frames_to_pop;
    160   }
    161 }
    162 
    163 base::TimeDelta AudioClock::ComputeBufferedMediaTime(int64_t frames) const {
    164   DCHECK_LE(frames, total_buffered_frames_);
    165 
    166   double scaled_frames = 0;
    167   for (size_t i = 0; i < buffered_.size() && frames > 0; ++i) {
    168     int64_t min_frames = std::min(buffered_[i].frames, frames);
    169     scaled_frames += min_frames * buffered_[i].playback_rate;
    170     frames -= min_frames;
    171   }
    172 
    173   return base::TimeDelta::FromMicroseconds(scaled_frames *
    174                                            microseconds_per_frame_);
    175 }
    176 
    177 }  // namespace media
    178